@authup/access 1.0.0-beta.27 → 1.0.0-beta.29

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.
Files changed (107) hide show
  1. package/LICENSE +201 -201
  2. package/dist/index.mjs +758 -541
  3. package/dist/index.mjs.map +1 -1
  4. package/dist/permission/checker/index.d.ts +3 -0
  5. package/dist/permission/checker/index.d.ts.map +1 -0
  6. package/dist/permission/{module.d.ts → checker/module.d.ts} +8 -7
  7. package/dist/permission/checker/module.d.ts.map +1 -0
  8. package/dist/permission/checker/types.d.ts +26 -0
  9. package/dist/permission/checker/types.d.ts.map +1 -0
  10. package/dist/permission/error/index.d.ts +0 -1
  11. package/dist/permission/error/index.d.ts.map +1 -1
  12. package/dist/permission/error/module.d.ts +4 -5
  13. package/dist/permission/error/module.d.ts.map +1 -1
  14. package/dist/permission/index.d.ts +2 -2
  15. package/dist/permission/index.d.ts.map +1 -1
  16. package/dist/permission/repository/index.d.ts.map +1 -0
  17. package/dist/permission/repository/memory.d.ts +9 -0
  18. package/dist/permission/repository/memory.d.ts.map +1 -0
  19. package/dist/permission/{provider → repository}/types.d.ts +2 -2
  20. package/dist/permission/repository/types.d.ts.map +1 -0
  21. package/dist/permission/types.d.ts +1 -19
  22. package/dist/permission/types.d.ts.map +1 -1
  23. package/dist/policy/built-in/attribute-names/evaluator.d.ts +5 -8
  24. package/dist/policy/built-in/attribute-names/evaluator.d.ts.map +1 -1
  25. package/dist/policy/built-in/attributes/evaluator.d.ts +5 -9
  26. package/dist/policy/built-in/attributes/evaluator.d.ts.map +1 -1
  27. package/dist/policy/built-in/attributes/validator.d.ts.map +1 -1
  28. package/dist/policy/built-in/composite/evaluator.d.ts +3 -8
  29. package/dist/policy/built-in/composite/evaluator.d.ts.map +1 -1
  30. package/dist/policy/built-in/composite/validator.d.ts.map +1 -1
  31. package/dist/policy/built-in/date/evaluator.d.ts +3 -8
  32. package/dist/policy/built-in/date/evaluator.d.ts.map +1 -1
  33. package/dist/policy/built-in/identity/data/index.d.ts +2 -0
  34. package/dist/policy/built-in/identity/data/index.d.ts.map +1 -0
  35. package/dist/policy/built-in/identity/data/validator.d.ts +6 -0
  36. package/dist/policy/built-in/identity/data/validator.d.ts.map +1 -0
  37. package/dist/policy/built-in/identity/evaluator.d.ts +7 -8
  38. package/dist/policy/built-in/identity/evaluator.d.ts.map +1 -1
  39. package/dist/policy/built-in/identity/types.d.ts +22 -0
  40. package/dist/policy/built-in/identity/types.d.ts.map +1 -1
  41. package/dist/policy/built-in/permission-binding/module.d.ts +3 -8
  42. package/dist/policy/built-in/permission-binding/module.d.ts.map +1 -1
  43. package/dist/policy/built-in/realm-match/evaluator.d.ts +7 -8
  44. package/dist/policy/built-in/realm-match/evaluator.d.ts.map +1 -1
  45. package/dist/policy/built-in/time/evaluator.d.ts +3 -8
  46. package/dist/policy/built-in/time/evaluator.d.ts.map +1 -1
  47. package/dist/policy/constants.d.ts +12 -0
  48. package/dist/policy/constants.d.ts.map +1 -0
  49. package/dist/policy/data.d.ts +20 -0
  50. package/dist/policy/data.d.ts.map +1 -0
  51. package/dist/policy/engine/module.d.ts +9 -9
  52. package/dist/policy/engine/module.d.ts.map +1 -1
  53. package/dist/policy/engine/types.d.ts +6 -3
  54. package/dist/policy/engine/types.d.ts.map +1 -1
  55. package/dist/policy/error/module.d.ts +5 -2
  56. package/dist/policy/error/module.d.ts.map +1 -1
  57. package/dist/policy/evaluation/context/define.d.ts +3 -0
  58. package/dist/policy/evaluation/context/define.d.ts.map +1 -0
  59. package/dist/policy/evaluation/context/index.d.ts +3 -0
  60. package/dist/policy/evaluation/context/index.d.ts.map +1 -0
  61. package/dist/policy/evaluation/context/types.d.ts +11 -0
  62. package/dist/policy/evaluation/context/types.d.ts.map +1 -0
  63. package/dist/policy/evaluation/index.d.ts +3 -0
  64. package/dist/policy/evaluation/index.d.ts.map +1 -0
  65. package/dist/policy/evaluation/types.d.ts +14 -0
  66. package/dist/policy/evaluation/types.d.ts.map +1 -0
  67. package/dist/policy/index.d.ts +4 -1
  68. package/dist/policy/index.d.ts.map +1 -1
  69. package/dist/policy/issue/constants.d.ts +21 -0
  70. package/dist/policy/issue/constants.d.ts.map +1 -0
  71. package/dist/policy/issue/define.d.ts +4 -0
  72. package/dist/policy/issue/define.d.ts.map +1 -0
  73. package/dist/policy/issue/index.d.ts +4 -0
  74. package/dist/policy/issue/index.d.ts.map +1 -0
  75. package/dist/policy/issue/types.d.ts +5 -0
  76. package/dist/policy/issue/types.d.ts.map +1 -0
  77. package/dist/policy/types.d.ts +3 -41
  78. package/dist/policy/types.d.ts.map +1 -1
  79. package/package.json +19 -15
  80. package/dist/index.cjs +0 -1055
  81. package/dist/index.cjs.map +0 -1
  82. package/dist/permission/error/types.d.ts +0 -11
  83. package/dist/permission/error/types.d.ts.map +0 -1
  84. package/dist/permission/module.d.ts.map +0 -1
  85. package/dist/permission/provider/index.d.ts.map +0 -1
  86. package/dist/permission/provider/memory.d.ts +0 -9
  87. package/dist/permission/provider/memory.d.ts.map +0 -1
  88. package/dist/permission/provider/types.d.ts.map +0 -1
  89. package/dist/policy/evaluator/data/identity/index.d.ts +0 -2
  90. package/dist/policy/evaluator/data/identity/index.d.ts.map +0 -1
  91. package/dist/policy/evaluator/data/identity/validator.d.ts +0 -6
  92. package/dist/policy/evaluator/data/identity/validator.d.ts.map +0 -1
  93. package/dist/policy/evaluator/data/index.d.ts +0 -4
  94. package/dist/policy/evaluator/data/index.d.ts.map +0 -1
  95. package/dist/policy/evaluator/data/permission/index.d.ts +0 -2
  96. package/dist/policy/evaluator/data/permission/index.d.ts.map +0 -1
  97. package/dist/policy/evaluator/data/permission/validator.d.ts +0 -6
  98. package/dist/policy/evaluator/data/permission/validator.d.ts.map +0 -1
  99. package/dist/policy/evaluator/data/validator.d.ts +0 -6
  100. package/dist/policy/evaluator/data/validator.d.ts.map +0 -1
  101. package/dist/policy/evaluator/evaluate.d.ts +0 -4
  102. package/dist/policy/evaluator/evaluate.d.ts.map +0 -1
  103. package/dist/policy/evaluator/index.d.ts +0 -4
  104. package/dist/policy/evaluator/index.d.ts.map +0 -1
  105. package/dist/policy/evaluator/types.d.ts +0 -44
  106. package/dist/policy/evaluator/types.d.ts.map +0 -1
  107. /package/dist/permission/{provider → repository}/index.d.ts +0 -0
package/dist/index.mjs CHANGED
@@ -1,28 +1,101 @@
1
1
  import { AuthupError, ErrorCode } from '@authup/errors';
2
+ import { defineIssueItem, defineIssueGroup, Container } from 'validup';
2
3
  import { isObject, flattenObject, hasOwnProperty } from '@authup/kit';
3
4
  import { createValidator } from '@validup/adapter-zod';
4
- import { Container } from 'validup';
5
5
  import { z } from 'zod';
6
6
  import { guard } from '@ucast/mongo2js';
7
7
 
8
- class PolicyError extends AuthupError {
9
- static evaluatorNotFound(type) {
10
- return new PolicyError(`No evaluator is registered to handle the policy: ${type}`, ErrorCode.POLICY_EVALUATOR_NOT_FOUND);
8
+ class PermissionError extends AuthupError {
9
+ constructor(options = {}){
10
+ super({
11
+ ...options,
12
+ message: options.message || 'A permission error occurred.',
13
+ statusCode: options.statusCode || 403
14
+ });
11
15
  }
12
- static evaluatorNotProcessable() {
13
- throw new PolicyError('The evaluator can not process the policy.', ErrorCode.POLICY_EVALUATOR_NOT_PROCESSABLE);
16
+ addIssue(data) {
17
+ this.issues.push(data);
14
18
  }
15
- static evaluatorContextInvalid() {
16
- throw new PolicyError('The evaluator context is not valid.', ErrorCode.POLICY_EVALUATOR_CONTEXT_INVALID);
19
+ addIssues(data) {
20
+ this.issues.push(...data);
17
21
  }
18
- constructor(message, code){
19
- super({
20
- message,
21
- code
22
+ static notFound(name) {
23
+ return new PermissionError({
24
+ message: `The permission ${name} was not found.`,
25
+ code: ErrorCode.PERMISSION_NOT_FOUND
26
+ });
27
+ }
28
+ static denied(name) {
29
+ return new PermissionError({
30
+ message: `The permission ${name} has not been granted.`,
31
+ code: ErrorCode.PERMISSION_DENIED
32
+ });
33
+ }
34
+ static deniedAll(names) {
35
+ return new PermissionError({
36
+ message: `None of the permissions ${names.join(', ')} has been granted.`,
37
+ code: ErrorCode.PERMISSION_DENIED
38
+ });
39
+ }
40
+ static evaluationFailed(name) {
41
+ if (Array.isArray(name)) {
42
+ return new PermissionError({
43
+ message: `The evaluation of permissions ${name.join(', ')} failed`,
44
+ code: ErrorCode.PERMISSION_EVALUATION_FAILED
45
+ });
46
+ }
47
+ return new PermissionError({
48
+ message: `The evaluation of permission ${name} failed`,
49
+ code: ErrorCode.PERMISSION_EVALUATION_FAILED
22
50
  });
23
51
  }
24
52
  }
25
53
 
54
+ /*
55
+ * Copyright (c) 2025.
56
+ * Author Peter Placzek (tada5hi)
57
+ * For the full copyright and license information,
58
+ * view the LICENSE file that was distributed with this source code.
59
+ */ function buildPermissionItemKey(input) {
60
+ return `${input.realmId || '_'}/${input.clientId || '_'}/${input.name}`;
61
+ }
62
+
63
+ /*
64
+ * Copyright (c) 2024-2024.
65
+ * Author Peter Placzek (tada5hi)
66
+ * For the full copyright and license information,
67
+ * view the LICENSE file that was distributed with this source code.
68
+ */ function isPermissionItemEqual(a, b) {
69
+ if (a.name !== b.name) {
70
+ return false;
71
+ }
72
+ if (typeof a.realmId === 'string' || typeof b.realmId === 'string') {
73
+ return a.realmId === b.realmId;
74
+ }
75
+ if (typeof a.clientId === 'string' || typeof b.clientId === 'string') {
76
+ return a.clientId === b.clientId;
77
+ }
78
+ return !!a.realmId === !!b.realmId && !!a.clientId === !!b.clientId;
79
+ }
80
+
81
+ /*
82
+ * Copyright (c) 2024-2024.
83
+ * Author Peter Placzek (tada5hi)
84
+ * For the full copyright and license information,
85
+ * view the LICENSE file that was distributed with this source code.
86
+ */ var DecisionStrategy = /*#__PURE__*/ function(DecisionStrategy) {
87
+ /**
88
+ * One or more positive
89
+ */ DecisionStrategy["AFFIRMATIVE"] = "affirmative";
90
+ /**
91
+ * All positive
92
+ */ DecisionStrategy["UNANIMOUS"] = "unanimous";
93
+ /**
94
+ * More positive than negative
95
+ */ DecisionStrategy["CONSENSUS"] = "consensus";
96
+ return DecisionStrategy;
97
+ }({});
98
+
26
99
  /*
27
100
  * Copyright (c) 2024-2024.
28
101
  * Author Peter Placzek (tada5hi)
@@ -41,6 +114,226 @@ class PolicyError extends AuthupError {
41
114
  return !outcome;
42
115
  }
43
116
 
117
+ class PolicyError extends AuthupError {
118
+ constructor(message, code){
119
+ super({
120
+ message,
121
+ code
122
+ });
123
+ }
124
+ addIssue(data) {
125
+ this.issues.push(data);
126
+ }
127
+ addIssues(data) {
128
+ this.issues.push(...data);
129
+ }
130
+ static evaluatorNotFound(type) {
131
+ return new PolicyError(`No evaluator is registered to handle the policy: ${type}`, ErrorCode.POLICY_EVALUATOR_NOT_FOUND);
132
+ }
133
+ static evaluatorNotProcessable() {
134
+ return new PolicyError('The evaluator can not process the policy.', ErrorCode.POLICY_EVALUATOR_NOT_PROCESSABLE);
135
+ }
136
+ static evaluatorContextInvalid() {
137
+ return new PolicyError('The evaluator context is not valid.', ErrorCode.POLICY_EVALUATOR_CONTEXT_INVALID);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * The policy engine is a component that interprets defined policies and makes decisions
143
+ * on whether to allow or deny a particular access.
144
+ */ class PolicyEngine {
145
+ evaluators;
146
+ constructor(evaluators = {}){
147
+ this.evaluators = evaluators;
148
+ }
149
+ registerEvaluator(type, evaluator) {
150
+ this.evaluators[type] = evaluator;
151
+ }
152
+ registerEvaluators(evaluators) {
153
+ const keys = Object.keys(evaluators);
154
+ for(let i = 0; i < keys.length; i++){
155
+ this.registerEvaluator(keys[i], evaluators[keys[i]]);
156
+ }
157
+ }
158
+ /**
159
+ * @param policy
160
+ * @param ctx
161
+ */ async evaluate(policy, ctx) {
162
+ if (ctx.exclude && ctx.exclude.length > 0 && ctx.exclude.indexOf(policy.type) !== -1) {
163
+ return {
164
+ success: maybeInvertPolicyOutcome(true, policy.invert)
165
+ };
166
+ }
167
+ if (ctx.include && ctx.include.length > 0 && ctx.include.indexOf(policy.type) === -1) {
168
+ return {
169
+ success: maybeInvertPolicyOutcome(true, policy.invert)
170
+ };
171
+ }
172
+ const issues = [];
173
+ const evaluator = this.evaluators[policy.type];
174
+ if (!evaluator) {
175
+ // todo: add issue here instead + return false ?
176
+ issues.push(defineIssueItem({
177
+ path: [
178
+ policy.type
179
+ ],
180
+ message: `The policy ${policy.type} can not be handled by any evaluator.`,
181
+ code: ErrorCode.POLICY_EVALUATOR_NOT_FOUND
182
+ }));
183
+ return {
184
+ success: maybeInvertPolicyOutcome(false, policy.invert),
185
+ issues
186
+ };
187
+ }
188
+ try {
189
+ return await evaluator.evaluate(policy, {
190
+ ...ctx,
191
+ evaluators: {
192
+ ...this.evaluators,
193
+ ...ctx.evaluators || {}
194
+ }
195
+ });
196
+ } catch (e) {
197
+ issues.push(defineIssueItem({
198
+ path: [
199
+ policy.type
200
+ ],
201
+ message: `The ${policy.type} evaluator can not process the policy specification.`,
202
+ code: ErrorCode.POLICY_EVALUATOR_NOT_PROCESSABLE
203
+ }));
204
+ return {
205
+ success: maybeInvertPolicyOutcome(false, policy.invert),
206
+ issues
207
+ };
208
+ }
209
+ }
210
+ async evaluateOrFail(policy, ctx) {
211
+ const issues = [];
212
+ try {
213
+ const outcome = await this.evaluate(policy, ctx);
214
+ if (outcome.success) {
215
+ return;
216
+ }
217
+ if (outcome.issues) {
218
+ issues.push(...outcome.issues);
219
+ }
220
+ } catch (e) {
221
+ if (e instanceof PolicyError) {
222
+ throw e;
223
+ }
224
+ }
225
+ const error = new PolicyError(`The policy ${policy.type} evaluation failed.`);
226
+ error.addIssues(issues);
227
+ throw error;
228
+ }
229
+ }
230
+
231
+ /*
232
+ * Copyright (c) 2026.
233
+ * Author Peter Placzek (tada5hi)
234
+ * For the full copyright and license information,
235
+ * view the LICENSE file that was distributed with this source code.
236
+ */ class PolicyData {
237
+ data;
238
+ validated;
239
+ constructor(data = {}, validated = new Set()){
240
+ this.data = data;
241
+ this.validated = validated;
242
+ }
243
+ set(key, value) {
244
+ this.data[key] = value;
245
+ this.validated.delete(key);
246
+ }
247
+ get(key) {
248
+ if (key in this.data) {
249
+ return this.data[key];
250
+ }
251
+ throw new Error(`Policy data item ${key} does not exist.`);
252
+ }
253
+ has(key) {
254
+ return key in this.data;
255
+ }
256
+ setValidated(key) {
257
+ this.validated.add(key);
258
+ }
259
+ isValidated(key) {
260
+ return this.validated.has(key);
261
+ }
262
+ clone() {
263
+ return new PolicyData({
264
+ ...this.data
265
+ }, new Set(this.validated));
266
+ }
267
+ }
268
+
269
+ function definePolicyEvaluationContext(input = {}) {
270
+ return {
271
+ evaluators: input.evaluators || {},
272
+ path: input.path || [],
273
+ data: input.data || new PolicyData(),
274
+ include: input.include || [],
275
+ exclude: input.exclude || []
276
+ };
277
+ }
278
+
279
+ /*
280
+ * Copyright (c) 2026-2026.
281
+ * Author Peter Placzek (tada5hi)
282
+ * For the full copyright and license information,
283
+ * view the LICENSE file that was distributed with this source code.
284
+ */ var PolicyIssueSeverity = /*#__PURE__*/ function(PolicyIssueSeverity) {
285
+ PolicyIssueSeverity["WARNING"] = "warning";
286
+ PolicyIssueSeverity["ERROR"] = "error";
287
+ return PolicyIssueSeverity;
288
+ }({});
289
+ var PolicyIssueCode = /*#__PURE__*/ function(PolicyIssueCode) {
290
+ // Data/Input
291
+ PolicyIssueCode["DATA_MISSING"] = "DATA_MISSING";
292
+ PolicyIssueCode["DATA_INVALID"] = "DATA_INVALID";
293
+ // Policy Spec / Config
294
+ PolicyIssueCode["INVALID"] = "INVALID";
295
+ PolicyIssueCode["TYPE_UNKNOWN"] = "TYPE_UNKNOWN";
296
+ PolicyIssueCode["FIELD_MISSING"] = "FIELD_MISSING";
297
+ PolicyIssueCode["FIELD_INVALID"] = "FIELD_INVALID";
298
+ // Composite / Tree evaluation
299
+ PolicyIssueCode["CHILD_INVALID"] = "CHILD_INVALID";
300
+ PolicyIssueCode["CHILD_EVALUATION_FAILED"] = "CHILD_EVALUATION_FAILED";
301
+ // Engine / Evaluator registry
302
+ PolicyIssueCode["EVALUATION_DENIED"] = "EVALUATION_DENIED";
303
+ PolicyIssueCode["EVALUATOR_NOT_FOUND"] = "EVALUATOR_NOT_FOUND";
304
+ PolicyIssueCode["EVALUATOR_ERROR"] = "EVALUATOR_ERROR";
305
+ // Execution control
306
+ PolicyIssueCode["SKIPPED_EXCLUDED"] = "SKIPPED_EXCLUDED";
307
+ PolicyIssueCode["SKIPPED_NOT_INCLUDED"] = "SKIPPED_NOT_INCLUDED";
308
+ // Internal / unexpected
309
+ PolicyIssueCode["INTERNAL_ERROR"] = "INTERNAL_ERROR";
310
+ return PolicyIssueCode;
311
+ }({});
312
+
313
+ function definePolicyIssueItem(input) {
314
+ return defineIssueItem(input);
315
+ }
316
+ function definePolicyIssueGroup(input) {
317
+ return defineIssueGroup(input);
318
+ }
319
+
320
+ class AttributeNamesPolicyValidator extends Container {
321
+ initialize() {
322
+ super.initialize();
323
+ this.mount('names', createValidator(z.array(z.string().min(3).max(128))));
324
+ this.mount('invert', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
325
+ }
326
+ }
327
+
328
+ /*
329
+ * Copyright (c) 2025.
330
+ * Author Peter Placzek (tada5hi)
331
+ * For the full copyright and license information,
332
+ * view the LICENSE file that was distributed with this source code.
333
+ */ function defineAttributesPolicy(data) {
334
+ return data;
335
+ }
336
+
44
337
  /*
45
338
  * Copyright (c) 2024-2024.
46
339
  * Author Peter Placzek (tada5hi)
@@ -74,277 +367,218 @@ class PolicyError extends AuthupError {
74
367
  return BuiltInPolicyType;
75
368
  }({});
76
369
 
77
- class AttributeNamesPolicyValidator extends Container {
78
- initialize() {
79
- super.initialize();
80
- this.mount('names', createValidator(z.array(z.string().min(3).max(128))));
81
- this.mount('invert', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
82
- }
83
- }
84
-
85
- class AttributeNamesPolicyEvaluator {
86
- async can(ctx) {
87
- return ctx.config.type === BuiltInPolicyType.ATTRIBUTE_NAMES;
88
- }
89
- async validateConfig(ctx) {
90
- return this.validator.run(ctx.config);
91
- }
92
- async validateInput(ctx) {
93
- if (!isObject(ctx.input.attributes)) {
94
- throw PolicyError.evaluatorContextInvalid();
95
- }
96
- return ctx.input;
97
- }
98
- async evaluate(ctx) {
99
- if (!ctx.input.attributes) {
100
- throw PolicyError.evaluatorContextInvalid();
101
- }
102
- const attributes = flattenObject(ctx.input.attributes);
103
- const keys = Object.keys(attributes);
104
- for(let i = 0; i < keys.length; i++){
105
- const index = ctx.config.names.indexOf(keys[i]);
106
- if (index === -1) {
107
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
108
- }
109
- }
110
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
111
- }
112
- constructor(){
113
- this.validator = new AttributeNamesPolicyValidator();
114
- }
115
- }
116
-
117
- /*
118
- * Copyright (c) 2025.
119
- * Author Peter Placzek (tada5hi)
120
- * For the full copyright and license information,
121
- * view the LICENSE file that was distributed with this source code.
122
- */ function defineAttributesPolicy(data) {
123
- return data;
124
- }
125
-
126
370
  class AttributesPolicyValidator extends Container {
127
371
  initialize() {
128
372
  super.initialize();
129
- this.mount('query', createValidator(z.object({}).passthrough()));
373
+ this.mount('query', createValidator(z.looseObject({})));
130
374
  this.mount('invert', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
131
375
  }
132
376
  }
133
377
 
134
378
  class AttributesPolicyEvaluator {
135
- async can(ctx) {
136
- return ctx.config.type === BuiltInPolicyType.ATTRIBUTES;
137
- }
138
- async validateConfig(ctx) {
139
- return this.validator.run(ctx.config);
379
+ validator;
380
+ constructor(){
381
+ this.validator = new AttributesPolicyValidator();
140
382
  }
141
- async validateInput(ctx) {
142
- if (!isObject(ctx.input.attributes)) {
143
- throw PolicyError.evaluatorContextInvalid();
383
+ async accessData(ctx) {
384
+ if (!ctx.data.has(BuiltInPolicyType.ATTRIBUTES)) {
385
+ return null;
144
386
  }
145
- return ctx.input;
146
- }
147
- async evaluate(ctx) {
148
- if (!ctx.input.attributes) {
149
- throw PolicyError.evaluatorContextInvalid();
387
+ if (ctx.data.isValidated(BuiltInPolicyType.ATTRIBUTES)) {
388
+ return ctx.data.get(BuiltInPolicyType.ATTRIBUTES);
389
+ }
390
+ // todo: run validator on attributes (isObject ...)
391
+ const data = ctx.data.get(BuiltInPolicyType.ATTRIBUTES);
392
+ ctx.data.set(BuiltInPolicyType.ATTRIBUTES, data);
393
+ ctx.data.setValidated(BuiltInPolicyType.ATTRIBUTES);
394
+ return data;
395
+ }
396
+ async evaluate(value, ctx) {
397
+ // todo: catch errors + transform to issue(s)
398
+ const policy = await this.validator.run(value);
399
+ const data = await this.accessData(ctx);
400
+ if (!data) {
401
+ return {
402
+ success: false,
403
+ issues: [
404
+ definePolicyIssueItem({
405
+ code: PolicyIssueCode.DATA_MISSING,
406
+ message: 'The data property attributes is missing',
407
+ path: ctx.path
408
+ })
409
+ ]
410
+ };
150
411
  }
151
- this.fixQuery(ctx.config.query);
152
- const testIt = guard(ctx.config.query);
153
- return maybeInvertPolicyOutcome(testIt(ctx.input.attributes), ctx.config.invert);
412
+ this.fixQuery(policy.query);
413
+ const testIt = guard(policy.query);
414
+ return {
415
+ success: maybeInvertPolicyOutcome(testIt(data), policy.invert)
416
+ };
154
417
  }
155
418
  fixQuery(query) {
156
- const keys = Object.keys(query);
157
- for(let i = 0; i < keys.length; i++){
158
- const key = keys[i];
159
- const value = query[key];
160
- if (isObject(value) || Array.isArray(value)) {
161
- this.fixQuery(value);
162
- continue;
419
+ if (Array.isArray(query)) {
420
+ for(let i = 0; i < query.length; i++){
421
+ this.fixQuery(query[i]);
163
422
  }
164
- if (key === '$regex' && typeof value === 'string') {
165
- const fragments = value.match(/\/(.*?)\/([a-z]*)?$/i);
166
- if (fragments) {
167
- query[key] = new RegExp(fragments[1], fragments[2]);
423
+ return;
424
+ }
425
+ if (isObject(query)) {
426
+ const keys = Object.keys(query);
427
+ for(let i = 0; i < keys.length; i++){
428
+ const key = keys[i];
429
+ const value = query[key];
430
+ if (isObject(value) || Array.isArray(value)) {
431
+ this.fixQuery(value);
432
+ continue;
433
+ }
434
+ if (key === '$regex' && typeof value === 'string') {
435
+ const fragments = value.match(/\/(.*?)\/([a-z]*)?$/i);
436
+ if (fragments) {
437
+ query[key] = new RegExp(fragments[1], fragments[2]);
438
+ }
168
439
  }
169
440
  }
170
441
  }
171
442
  }
172
- constructor(){
173
- this.validator = new AttributesPolicyValidator();
174
- }
175
443
  }
176
444
 
177
- /*
178
- * Copyright (c) 2024-2024.
179
- * Author Peter Placzek (tada5hi)
180
- * For the full copyright and license information,
181
- * view the LICENSE file that was distributed with this source code.
182
- */ var DecisionStrategy = /*#__PURE__*/ function(DecisionStrategy) {
183
- /**
184
- * One or more positive
185
- */ DecisionStrategy["AFFIRMATIVE"] = "affirmative";
186
- /**
187
- * All positive
188
- */ DecisionStrategy["UNANIMOUS"] = "unanimous";
189
- /**
190
- * More positive than negative
191
- */ DecisionStrategy["CONSENSUS"] = "consensus";
192
- return DecisionStrategy;
193
- }({});
194
-
195
- class PolicyDataIdentityValidator extends Container {
196
- initialize() {
197
- super.initialize();
198
- this.mount('type', createValidator(z.string().min(3).max(128)));
199
- this.mount('id', createValidator(z.string().uuid()));
200
- this.mount('clientId', createValidator(z.string().uuid().or(z.null()).or(z.undefined()).optional()));
201
- this.mount('realmId', createValidator(z.string().uuid().or(z.null()).or(z.undefined()).optional()));
202
- this.mount('realmName', createValidator(z.string().min(3).max(128).or(z.null()).or(z.undefined()).optional()));
203
- }
204
- }
205
-
206
- class PolicyDataPermissionValidator extends Container {
207
- initialize() {
208
- super.initialize();
209
- this.mount('name', createValidator(z.string().min(3).max(256)));
210
- this.mount('clientId', createValidator(z.string().uuid().or(z.null()).or(z.undefined()).optional()));
211
- this.mount('realmId', createValidator(z.string().uuid().or(z.null()).or(z.undefined()).optional()));
212
- this.mount('policy', createValidator(z.object({
213
- type: z.string()
214
- }).optional()));
215
- }
216
- }
217
-
218
- class PolicyDataValidator extends Container {
219
- initialize() {
220
- super.initialize();
221
- // todo: optionalValue should be null
222
- const identity = new PolicyDataIdentityValidator();
223
- this.mount('identity', {
224
- optional: true,
225
- optionalValue: 'undefined',
226
- optionalInclude: true
227
- }, identity);
228
- // todo: optionalValue should be null
229
- const permission = new PolicyDataPermissionValidator();
230
- this.mount('permission', {
231
- optional: true,
232
- optionalValue: 'undefined',
233
- optionalInclude: true
234
- }, permission);
235
- this.mount('attributes', createValidator(z.object({}).optional()));
236
- this.mount('dateTime', createValidator(z.date().or(z.string()).or(z.number()).optional()));
237
- }
238
- }
239
-
240
- async function evaluatePolicy(ctx) {
241
- if (ctx.options.exclude && ctx.options.exclude.length > 0 && ctx.options.exclude.indexOf(ctx.config.type) !== -1) {
242
- if (typeof ctx.config.invert === 'boolean') {
243
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
244
- }
245
- return true;
246
- }
247
- if (ctx.options.include && ctx.options.include.length > 0 && ctx.options.include.indexOf(ctx.config.type) === -1) {
248
- if (typeof ctx.config.invert === 'boolean') {
249
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
250
- }
251
- return true;
252
- }
253
- const evaluator = ctx.evaluators[ctx.config.type];
254
- if (!evaluator) {
255
- throw PolicyError.evaluatorNotFound(ctx.config.type);
256
- }
257
- try {
258
- const canEvaluate = await evaluator.can(ctx);
259
- if (canEvaluate) {
260
- const config = await evaluator.validateConfig(ctx);
261
- const input = await evaluator.validateInput(ctx);
262
- return await evaluator.evaluate({
263
- ...ctx,
264
- input,
265
- config
266
- });
267
- }
268
- } catch (e) {
269
- if (e instanceof PolicyError) {
270
- throw e;
445
+ class AttributeNamesPolicyEvaluator {
446
+ validator;
447
+ attributesEvaluator;
448
+ constructor(){
449
+ this.validator = new AttributeNamesPolicyValidator();
450
+ this.attributesEvaluator = new AttributesPolicyEvaluator();
451
+ }
452
+ async evaluate(value, ctx) {
453
+ // todo: catch errors + transform to issue(s)
454
+ const policy = await this.validator.run(value);
455
+ const data = await this.attributesEvaluator.accessData(ctx);
456
+ if (!data) {
457
+ return {
458
+ success: false,
459
+ issues: [
460
+ definePolicyIssueItem({
461
+ code: PolicyIssueCode.DATA_MISSING,
462
+ message: 'The data property attributes is missing',
463
+ path: ctx.path
464
+ })
465
+ ]
466
+ };
271
467
  }
272
- if (e instanceof Error) {
273
- const error = new PolicyError(e.message);
274
- error.stack = e.stack;
275
- throw error;
468
+ const attributes = flattenObject(data);
469
+ const keys = Object.keys(attributes);
470
+ const issues = [];
471
+ for(let i = 0; i < keys.length; i++){
472
+ const index = policy.names.indexOf(keys[i]);
473
+ if (index === -1) {
474
+ issues.push(definePolicyIssueItem({
475
+ code: PolicyIssueCode.EVALUATION_DENIED,
476
+ message: `The attribute ${keys[i]} is not included`,
477
+ path: [
478
+ ...ctx.path,
479
+ keys[i]
480
+ ]
481
+ }));
482
+ }
276
483
  }
277
- throw new PolicyError();
484
+ return {
485
+ success: maybeInvertPolicyOutcome(issues.length === 0, policy.invert),
486
+ issues
487
+ };
278
488
  }
279
- throw PolicyError.evaluatorNotProcessable();
280
- }
281
-
282
- function isCompositePolicy(input) {
283
- return input.type === BuiltInPolicyType.COMPOSITE;
284
489
  }
285
490
 
286
491
  class CompositePolicyValidator extends Container {
287
492
  initialize() {
288
493
  super.initialize();
289
- this.mount('decisionStrategy', createValidator(z.nativeEnum(DecisionStrategy).or(z.null()).or(z.undefined()).optional()));
290
- this.mount('children', createValidator(z.array(z.object({
494
+ this.mount('decisionStrategy', createValidator(z.enum(DecisionStrategy).or(z.null()).or(z.undefined()).optional()));
495
+ this.mount('children', createValidator(z.array(z.looseObject({
291
496
  type: z.string().min(3)
292
- }).passthrough())));
497
+ }))));
293
498
  this.mount('invert', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
294
499
  }
295
500
  }
296
501
 
297
502
  class CompositePolicyEvaluator {
298
- async can(ctx) {
299
- return isCompositePolicy(ctx.config);
300
- }
301
- async validateConfig(ctx) {
302
- return this.validator.run(ctx.config);
303
- }
304
- async validateInput(ctx) {
305
- return ctx.input;
503
+ validator;
504
+ constructor(){
505
+ this.validator = new CompositePolicyValidator();
306
506
  }
307
- async evaluate(ctx) {
507
+ async evaluate(value, ctx) {
508
+ // todo: catch errors + transform to issue(s)
509
+ const policy = await this.validator.run(value);
308
510
  let count = 0;
309
- const decisionStrategy = ctx.config.decisionStrategy ?? DecisionStrategy.UNANIMOUS;
310
- for(let i = 0; i < ctx.config.children.length; i++){
311
- const childPolicy = ctx.config.children[i];
312
- let outcome;
313
- if (isCompositePolicy(childPolicy)) {
314
- outcome = await this.evaluate({
315
- ...ctx,
316
- config: childPolicy
317
- });
318
- } else {
319
- outcome = await evaluatePolicy({
320
- ...ctx,
321
- config: childPolicy
322
- });
323
- }
324
- if (outcome) {
511
+ const decisionStrategy = policy.decisionStrategy ?? DecisionStrategy.UNANIMOUS;
512
+ const engine = new PolicyEngine(ctx.evaluators);
513
+ const issues = [];
514
+ for(let i = 0; i < policy.children.length; i++){
515
+ const childPolicy = policy.children[i];
516
+ const path = [
517
+ ...ctx.path || [],
518
+ childPolicy.type
519
+ ];
520
+ const outcome = await engine.evaluate(childPolicy, {
521
+ ...ctx,
522
+ path
523
+ });
524
+ if (outcome.success) {
325
525
  if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
326
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
526
+ return {
527
+ success: maybeInvertPolicyOutcome(true, policy.invert),
528
+ issues: []
529
+ };
327
530
  }
328
531
  count++;
329
532
  } else {
533
+ if (outcome.issues) {
534
+ issues.push(defineIssueGroup({
535
+ message: `The evaluation of child policy ${childPolicy.type} failed`,
536
+ issues: outcome.issues || [],
537
+ path
538
+ }));
539
+ }
330
540
  if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
331
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
541
+ return {
542
+ success: maybeInvertPolicyOutcome(false, policy.invert),
543
+ issues: [
544
+ defineIssueGroup({
545
+ message: `The evaluation of composite policy failed (${DecisionStrategy.UNANIMOUS})`,
546
+ issues,
547
+ path: ctx.path
548
+ })
549
+ ]
550
+ };
332
551
  }
333
552
  count--;
334
553
  }
335
554
  }
336
- return maybeInvertPolicyOutcome(count > 0, ctx.config.invert);
337
- }
338
- constructor(){
339
- this.validator = new CompositePolicyValidator();
555
+ if (count > 0) {
556
+ return {
557
+ success: maybeInvertPolicyOutcome(true, policy.invert)
558
+ };
559
+ }
560
+ return {
561
+ success: maybeInvertPolicyOutcome(false, policy.invert),
562
+ issues: [
563
+ defineIssueGroup({
564
+ message: `The evaluation of composite policy failed (${DecisionStrategy.CONSENSUS})`,
565
+ issues: issues || [],
566
+ path: ctx.path
567
+ })
568
+ ]
569
+ };
340
570
  }
341
571
  }
342
572
 
573
+ function isCompositePolicy(input) {
574
+ return input.type === BuiltInPolicyType.COMPOSITE;
575
+ }
576
+
343
577
  class DatePolicyValidator extends Container {
344
578
  initialize() {
345
579
  super.initialize();
346
- this.mount('start', createValidator(z.date().or(z.string().date()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
347
- this.mount('end', createValidator(z.date().or(z.string().date()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
580
+ this.mount('start', createValidator(z.date().or(z.iso.date()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
581
+ this.mount('end', createValidator(z.date().or(z.iso.date()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
348
582
  this.mount('invert', createValidator(z.boolean().or(z.undefined()).or(z.null()).optional()));
349
583
  }
350
584
  }
@@ -362,38 +596,56 @@ function toDate$1(input) {
362
596
  return input;
363
597
  }
364
598
  class DatePolicyEvaluator {
365
- async can(ctx) {
366
- return ctx.config.type === BuiltInPolicyType.DATE;
367
- }
368
- async validateConfig(ctx) {
369
- return this.validator.run(ctx.config);
370
- }
371
- async validateInput(ctx) {
372
- return ctx.input;
599
+ validator;
600
+ constructor(){
601
+ this.validator = new DatePolicyValidator();
373
602
  }
374
- async evaluate(ctx) {
603
+ async evaluate(value, ctx) {
604
+ // todo: catch errors + transform to issue(s)
605
+ const policy = await this.validator.run(value);
375
606
  let now;
376
- if (ctx.input.dateTime) {
377
- now = normalizeDate$1(toDate$1(ctx.input.dateTime));
607
+ if (ctx.data.has(BuiltInPolicyType.DATE)) {
608
+ if (ctx.data.isValidated(BuiltInPolicyType.DATE)) {
609
+ now = ctx.data.get(BuiltInPolicyType.DATE);
610
+ } else {
611
+ // todo: run validator on attributes (isObject ...)
612
+ now = normalizeDate$1(toDate$1(ctx.data.get(BuiltInPolicyType.DATE)));
613
+ ctx.data.set(BuiltInPolicyType.DATE, now);
614
+ ctx.data.setValidated(BuiltInPolicyType.DATE);
615
+ }
378
616
  } else {
379
617
  now = normalizeDate$1(new Date());
380
618
  }
381
- if (ctx.config.start) {
382
- const start = normalizeDate$1(toDate$1(ctx.config.start));
619
+ if (policy.start) {
620
+ const start = normalizeDate$1(toDate$1(policy.start));
383
621
  if (now < start) {
384
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
622
+ return {
623
+ success: maybeInvertPolicyOutcome(false, policy.invert)
624
+ };
385
625
  }
386
626
  }
387
- if (ctx.config.end) {
388
- const end = normalizeDate$1(toDate$1(ctx.config.end));
627
+ if (policy.end) {
628
+ const end = normalizeDate$1(toDate$1(policy.end));
389
629
  if (now > end) {
390
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
630
+ return {
631
+ success: maybeInvertPolicyOutcome(false, policy.invert)
632
+ };
391
633
  }
392
634
  }
393
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
635
+ return {
636
+ success: maybeInvertPolicyOutcome(true, policy.invert)
637
+ };
394
638
  }
395
- constructor(){
396
- this.validator = new DatePolicyValidator();
639
+ }
640
+
641
+ class PolicyIdentityDataValidator extends Container {
642
+ initialize() {
643
+ super.initialize();
644
+ this.mount('type', createValidator(z.string().min(3).max(128)));
645
+ this.mount('id', createValidator(z.uuid()));
646
+ this.mount('clientId', createValidator(z.uuid().or(z.null()).or(z.undefined()).optional()));
647
+ this.mount('realmId', createValidator(z.uuid().or(z.null()).or(z.undefined()).optional()));
648
+ this.mount('realmName', createValidator(z.string().min(3).max(128).or(z.null()).or(z.undefined()).optional()));
397
649
  }
398
650
  }
399
651
 
@@ -405,28 +657,61 @@ class IdentityPolicyValidator extends Container {
405
657
  }
406
658
 
407
659
  class IdentityPolicyEvaluator {
408
- async can(ctx) {
409
- return ctx.config.type === BuiltInPolicyType.IDENTITY;
410
- }
411
- async validateConfig(ctx) {
412
- return this.validator.run(ctx.config);
413
- }
414
- async validateInput(ctx) {
415
- return ctx.input;
660
+ validator;
661
+ dataValidator;
662
+ constructor(){
663
+ this.validator = new IdentityPolicyValidator();
664
+ this.dataValidator = new PolicyIdentityDataValidator();
416
665
  }
417
- async evaluate(ctx) {
418
- if (!isObject(ctx.input.identity)) {
419
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
666
+ async accessData(ctx) {
667
+ if (!ctx.data.has('identity')) {
668
+ return null;
420
669
  }
421
- const types = ctx.config.types || [];
422
- if (types.length === 0) {
423
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
670
+ if (ctx.data.isValidated('identity')) {
671
+ return ctx.data.get('identity');
424
672
  }
425
- const typeAllowed = types.indexOf(ctx.input.identity.type) !== -1;
426
- return maybeInvertPolicyOutcome(typeAllowed, ctx.config.invert);
427
- }
428
- constructor(){
429
- this.validator = new IdentityPolicyValidator();
673
+ const data = await this.dataValidator.run(ctx.data.get('identity'));
674
+ ctx.data.set('identity', data);
675
+ ctx.data.setValidated('identity');
676
+ return data;
677
+ }
678
+ async evaluate(value, ctx) {
679
+ // todo: catch errors + transform to issue(s)
680
+ const policy = await this.validator.run(value);
681
+ const data = await this.accessData(ctx);
682
+ if (!data) {
683
+ return {
684
+ success: false,
685
+ issues: [
686
+ definePolicyIssueItem({
687
+ code: PolicyIssueCode.DATA_MISSING,
688
+ message: 'The data property identity is missing',
689
+ path: ctx.path
690
+ })
691
+ ]
692
+ };
693
+ }
694
+ if (!policy.types || policy.types.length === 0) {
695
+ return {
696
+ success: maybeInvertPolicyOutcome(true, policy.invert)
697
+ };
698
+ }
699
+ const typeAllowed = policy.types.indexOf(data.type) !== -1;
700
+ if (typeAllowed) {
701
+ return {
702
+ success: maybeInvertPolicyOutcome(typeAllowed, policy.invert)
703
+ };
704
+ }
705
+ return {
706
+ success: maybeInvertPolicyOutcome(typeAllowed, policy.invert),
707
+ issues: [
708
+ definePolicyIssueItem({
709
+ code: PolicyIssueCode.EVALUATION_DENIED,
710
+ message: `The type ${data.type} is not covered by the policy configuration`,
711
+ path: ctx.path
712
+ })
713
+ ]
714
+ };
430
715
  }
431
716
  }
432
717
 
@@ -435,31 +720,23 @@ class PermissionBindingPolicyValidator extends Container {
435
720
  }
436
721
 
437
722
  class PermissionBindingPolicyEvaluator {
438
- async can(ctx) {
439
- return ctx.config.type === BuiltInPolicyType.PERMISSION_BINDING;
440
- }
441
- async validateConfig(ctx) {
442
- return this.validator.run(ctx.config);
443
- }
444
- async validateInput(ctx) {
445
- if (!isObject(ctx.input.identity) && !isObject(ctx.input.permission)) {
446
- throw PolicyError.evaluatorContextInvalid();
447
- }
448
- return ctx.input;
449
- }
450
- async evaluate(ctx) {
451
- // todo: this must be changed when the permission-checker not only checks owned permissions.
452
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
453
- }
723
+ validator;
454
724
  constructor(){
455
725
  this.validator = new PermissionBindingPolicyValidator();
456
726
  }
727
+ async evaluate(value) {
728
+ const policy = await this.validator.run(value);
729
+ // todo: this must be changed when the permission-checker not only checks owned permissions.
730
+ return {
731
+ success: maybeInvertPolicyOutcome(true, policy.invert)
732
+ };
733
+ }
457
734
  }
458
735
 
459
736
  class RealmMatchPolicyValidator extends Container {
460
737
  initialize() {
461
738
  super.initialize();
462
- this.mount('decisionStrategy', createValidator(z.nativeEnum(DecisionStrategy).or(z.null()).or(z.undefined()).optional()));
739
+ this.mount('decisionStrategy', createValidator(z.enum(DecisionStrategy).or(z.null()).or(z.undefined()).optional()));
463
740
  this.mount('attributeName', createValidator(z.string().min(3).or(z.array(z.string().min(3))).or(z.null()).or(z.undefined()).optional()));
464
741
  this.mount('attributeNameStrict', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
465
742
  this.mount('attributeNullMatchAll', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
@@ -469,33 +746,56 @@ class RealmMatchPolicyValidator extends Container {
469
746
  }
470
747
 
471
748
  class RealmMatchPolicyEvaluator {
472
- async can(ctx) {
473
- return ctx.config.type === BuiltInPolicyType.REALM_MATCH;
474
- }
475
- async validateConfig(ctx) {
476
- return this.validator.run(ctx.config);
477
- }
478
- async validateInput(ctx) {
479
- if (!isObject(ctx.input.attributes) || !isObject(ctx.input.identity)) {
480
- throw PolicyError.evaluatorContextInvalid();
749
+ validator;
750
+ identityEvaluator;
751
+ attributesEvaluator;
752
+ constructor(){
753
+ this.validator = new RealmMatchPolicyValidator();
754
+ this.identityEvaluator = new IdentityPolicyEvaluator();
755
+ this.attributesEvaluator = new AttributesPolicyEvaluator();
756
+ }
757
+ async evaluate(value, ctx) {
758
+ // todo: catch errors + transform to issue(s)
759
+ const policy = await this.validator.run(value);
760
+ const identity = await this.identityEvaluator.accessData(ctx);
761
+ if (!identity) {
762
+ return {
763
+ success: false,
764
+ issues: [
765
+ definePolicyIssueItem({
766
+ code: PolicyIssueCode.DATA_MISSING,
767
+ message: 'The data property identity is missing',
768
+ path: ctx.path
769
+ })
770
+ ]
771
+ };
481
772
  }
482
- return ctx.input;
483
- }
484
- async evaluate(ctx) {
485
- if (!ctx.input.attributes || !ctx.input.identity) {
486
- throw PolicyError.evaluatorContextInvalid();
773
+ const attributes = await this.attributesEvaluator.accessData(ctx);
774
+ if (!attributes) {
775
+ return {
776
+ success: false,
777
+ issues: [
778
+ definePolicyIssueItem({
779
+ code: PolicyIssueCode.DATA_MISSING,
780
+ message: 'The data property attributes is missing',
781
+ path: ctx.path
782
+ })
783
+ ]
784
+ };
487
785
  }
488
- const identityMasterMatchAll = ctx.config.identityMasterMatchAll ?? true;
489
- if (identityMasterMatchAll && ctx.input.identity.realmName && ctx.input.identity.realmName === 'master') {
490
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
786
+ const identityMasterMatchAll = policy.identityMasterMatchAll ?? true;
787
+ if (identityMasterMatchAll && identity.realmName && identity.realmName === 'master') {
788
+ return {
789
+ success: maybeInvertPolicyOutcome(true, policy.invert)
790
+ };
491
791
  }
492
792
  let keys;
493
- if (ctx.config.attributeName) {
494
- if (Array.isArray(ctx.config.attributeName)) {
495
- keys = ctx.config.attributeName;
793
+ if (policy.attributeName) {
794
+ if (Array.isArray(policy.attributeName)) {
795
+ keys = policy.attributeName;
496
796
  } else {
497
797
  keys = [
498
- ctx.config.attributeName
798
+ policy.attributeName
499
799
  ];
500
800
  }
501
801
  } else {
@@ -505,11 +805,11 @@ class RealmMatchPolicyEvaluator {
505
805
  'realmId',
506
806
  'realmName'
507
807
  ];
508
- ctx.config.decisionStrategy = DecisionStrategy.CONSENSUS;
808
+ policy.decisionStrategy = DecisionStrategy.CONSENSUS;
509
809
  }
510
- const attributeNameStrict = ctx.config.attributeNameStrict ?? true;
810
+ const attributeNameStrict = policy.attributeNameStrict ?? true;
511
811
  if (!attributeNameStrict) {
512
- const resourceKeys = Object.keys(ctx.input.attributes);
812
+ const resourceKeys = Object.keys(attributes);
513
813
  const keysToAdd = [];
514
814
  for(let i = 0; i < resourceKeys.length; i++){
515
815
  let contains = false;
@@ -529,32 +829,35 @@ class RealmMatchPolicyEvaluator {
529
829
  }
530
830
  let count = 0;
531
831
  for(let i = 0; i < keys.length; i++){
532
- if (!hasOwnProperty(ctx.input.attributes, keys[i])) {
832
+ if (!hasOwnProperty(attributes, keys[i])) {
533
833
  continue;
534
834
  }
535
835
  let outcome = false;
536
- const attributeValue = ctx.input.attributes[keys[i]];
537
- if (attributeValue === null && ctx.config.attributeNullMatchAll) {
836
+ const attributeValue = attributes[keys[i]];
837
+ if (attributeValue === null && policy.attributeNullMatchAll) {
538
838
  outcome = true;
539
- } else if (attributeValue === ctx.input.identity.realmId || attributeValue === ctx.input.identity.realmName) {
839
+ } else if (attributeValue === identity.realmId || attributeValue === identity.realmName) {
540
840
  outcome = true;
541
841
  }
542
842
  if (outcome) {
543
- if (ctx.config.decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
544
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
843
+ if (policy.decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
844
+ return {
845
+ success: maybeInvertPolicyOutcome(true, policy.invert)
846
+ };
545
847
  }
546
848
  count++;
547
849
  } else {
548
- if (ctx.config.decisionStrategy === DecisionStrategy.UNANIMOUS) {
549
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
850
+ if (policy.decisionStrategy === DecisionStrategy.UNANIMOUS) {
851
+ return {
852
+ success: maybeInvertPolicyOutcome(false, policy.invert)
853
+ };
550
854
  }
551
855
  count--;
552
856
  }
553
857
  }
554
- return maybeInvertPolicyOutcome(count > 0, ctx.config.invert);
555
- }
556
- constructor(){
557
- this.validator = new RealmMatchPolicyValidator();
858
+ return {
859
+ success: maybeInvertPolicyOutcome(count > 0, policy.invert)
860
+ };
558
861
  }
559
862
  }
560
863
 
@@ -586,10 +889,10 @@ class TimePolicyValidator extends Container {
586
889
  super.initialize();
587
890
  this.mount('dayOfWeek', createValidator(z.number().min(0).max(6).or(z.null()).or(z.undefined()).optional()));
588
891
  this.mount('dayOfMonth', createValidator(z.number().min(1).max(31).or(z.null()).or(z.undefined()).optional()));
589
- this.mount('dayOfYear', createValidator(z.number().min(1).max(366).or(z.null()).or(z.undefined()).optional()));
590
- this.mount('start', createValidator(z.date().or(z.string().datetime()).or(z.string().time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
591
- this.mount('end', createValidator(z.date().or(z.string().datetime()).or(z.string().time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
592
- this.mount('interval', createValidator(z.nativeEnum(TimePolicyInterval).or(z.null()).or(z.undefined()).optional()));
892
+ this.mount('dayOfYear', createValidator(z.number().min(1).max(365).or(z.null()).or(z.undefined()).optional()));
893
+ this.mount('start', createValidator(z.date().or(z.iso.datetime()).or(z.iso.time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
894
+ this.mount('end', createValidator(z.date().or(z.iso.datetime()).or(z.iso.time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
895
+ this.mount('interval', createValidator(z.enum(TimePolicyInterval).or(z.null()).or(z.undefined()).optional()));
593
896
  this.mount('invert', createValidator(z.boolean().or(z.undefined()).or(z.null()).optional()));
594
897
  }
595
898
  }
@@ -616,59 +919,72 @@ function toDate(input, dateRef) {
616
919
  return input;
617
920
  }
618
921
  class TimePolicyEvaluator {
619
- async can(ctx) {
620
- return ctx.config.type === BuiltInPolicyType.TIME;
621
- }
622
- async validateConfig(ctx) {
623
- return this.validator.run(ctx.config);
624
- }
625
- async validateInput(ctx) {
626
- return ctx.input;
922
+ validator;
923
+ constructor(){
924
+ this.validator = new TimePolicyValidator();
627
925
  }
628
- async evaluate(ctx) {
926
+ async evaluate(value, ctx) {
927
+ // todo: catch errors + transform to issue(s)
928
+ const policy = await this.validator.run(value);
629
929
  let now;
630
- if (ctx.input.dateTime) {
631
- now = toDate(ctx.input.dateTime);
930
+ if (ctx.data.has(BuiltInPolicyType.TIME)) {
931
+ if (ctx.data.isValidated(BuiltInPolicyType.TIME)) {
932
+ now = ctx.data.get(BuiltInPolicyType.TIME);
933
+ } else {
934
+ // todo: run validator on attributes (isObject ...)
935
+ now = toDate(ctx.data.get(BuiltInPolicyType.TIME));
936
+ ctx.data.set(BuiltInPolicyType.TIME, now);
937
+ ctx.data.setValidated(BuiltInPolicyType.TIME);
938
+ }
632
939
  } else {
633
940
  now = new Date();
634
941
  }
635
- if (ctx.config.start) {
636
- const start = normalizeDate(toDate(ctx.config.start, now), now);
942
+ if (policy.start) {
943
+ const start = normalizeDate(toDate(policy.start, now), now);
637
944
  if (now < start) {
638
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
945
+ return {
946
+ success: maybeInvertPolicyOutcome(false, policy.invert)
947
+ };
639
948
  }
640
949
  }
641
- if (ctx.config.end) {
642
- const end = normalizeDate(toDate(ctx.config.end, now), now);
950
+ if (policy.end) {
951
+ const end = normalizeDate(toDate(policy.end, now), now);
643
952
  if (now > end) {
644
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
953
+ return {
954
+ success: maybeInvertPolicyOutcome(false, policy.invert)
955
+ };
645
956
  }
646
957
  }
647
- if (ctx.config.interval) {
648
- if (isIntervalForDayOfWeek(ctx.config.interval) && ctx.config.dayOfWeek) {
649
- if (now.getDay() !== ctx.config.dayOfWeek) {
650
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
958
+ if (policy.interval) {
959
+ if (isIntervalForDayOfWeek(policy.interval) && policy.dayOfWeek) {
960
+ if (now.getDay() !== policy.dayOfWeek) {
961
+ return {
962
+ success: maybeInvertPolicyOutcome(false, policy.invert)
963
+ };
651
964
  }
652
965
  }
653
- if (isIntervalForDayOfMonth(ctx.config.interval) && ctx.config.dayOfMonth) {
654
- if (now.getDate() !== ctx.config.dayOfMonth) {
655
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
966
+ if (isIntervalForDayOfMonth(policy.interval) && policy.dayOfMonth) {
967
+ if (now.getDate() !== policy.dayOfMonth) {
968
+ return {
969
+ success: maybeInvertPolicyOutcome(false, policy.invert)
970
+ };
656
971
  }
657
972
  }
658
- if (isIntervalForDayOfYear(ctx.config.interval) && ctx.config.dayOfYear) {
973
+ if (isIntervalForDayOfYear(policy.interval) && policy.dayOfYear) {
659
974
  const start = new Date(now.getFullYear(), 0, 0);
660
975
  const diff = now.getTime() - start.getTime() + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
661
976
  const oneDay = 1000 * 60 * 60 * 24;
662
977
  const dayOfYear = Math.floor(diff / oneDay);
663
- if (dayOfYear !== ctx.config.dayOfYear) {
664
- return maybeInvertPolicyOutcome(false, ctx.config.invert);
978
+ if (dayOfYear !== policy.dayOfYear) {
979
+ return {
980
+ success: maybeInvertPolicyOutcome(false, policy.invert)
981
+ };
665
982
  }
666
983
  }
667
984
  }
668
- return maybeInvertPolicyOutcome(true, ctx.config.invert);
669
- }
670
- constructor(){
671
- this.validator = new TimePolicyValidator();
985
+ return {
986
+ success: maybeInvertPolicyOutcome(true, policy.invert)
987
+ };
672
988
  }
673
989
  }
674
990
 
@@ -684,117 +1000,16 @@ class TimePolicyEvaluator {
684
1000
  };
685
1001
  }
686
1002
 
687
- /**
688
- * The policy engine is a component that interprets defined policies and makes decisions
689
- * on whether to allow or deny a particular access.
690
- */ class PolicyEngine {
691
- registerEvaluator(type, evaluator) {
692
- this.evaluators[type] = evaluator;
693
- }
694
- registerEvaluators(evaluators) {
695
- const keys = Object.keys(evaluators);
696
- for(let i = 0; i < keys.length; i++){
697
- this.registerEvaluator(keys[i], evaluators[keys[i]]);
698
- }
699
- }
700
- registerDefaultEvaluators() {
701
- this.registerEvaluator(BuiltInPolicyType.COMPOSITE, new CompositePolicyEvaluator());
702
- this.registerEvaluator(BuiltInPolicyType.ATTRIBUTES, new AttributesPolicyEvaluator());
703
- this.registerEvaluator(BuiltInPolicyType.ATTRIBUTE_NAMES, new AttributeNamesPolicyEvaluator());
704
- this.registerEvaluator(BuiltInPolicyType.DATE, new DatePolicyEvaluator());
705
- this.registerEvaluator(BuiltInPolicyType.IDENTITY, new IdentityPolicyEvaluator());
706
- this.registerEvaluator(BuiltInPolicyType.PERMISSION_BINDING, new PermissionBindingPolicyEvaluator());
707
- this.registerEvaluator(BuiltInPolicyType.REALM_MATCH, new RealmMatchPolicyEvaluator());
708
- this.registerEvaluator(BuiltInPolicyType.TIME, new TimePolicyEvaluator());
709
- }
710
- /**
711
- * @throws PolicyError
712
- *
713
- * @param ctx
714
- */ async evaluate(ctx) {
715
- return evaluatePolicy({
716
- ...ctx,
717
- options: ctx.options || {},
718
- evaluators: this.evaluators
719
- });
720
- }
721
- constructor(evaluators = {}){
722
- this.evaluators = {};
723
- this.registerDefaultEvaluators();
724
- this.registerEvaluators(evaluators);
725
- }
726
- }
727
-
728
- class PermissionError extends AuthupError {
729
- static notFound(name) {
730
- return new PermissionError({
731
- message: `The permission ${name} was not found.`,
732
- code: ErrorCode.PERMISSION_NOT_FOUND
733
- });
734
- }
735
- static denied(name) {
736
- return new PermissionError({
737
- message: `The permission ${name} has not been granted.`,
738
- code: ErrorCode.PERMISSION_DENIED
739
- });
740
- }
741
- static deniedAll(names) {
742
- return new PermissionError({
743
- message: `None of the permissions ${names.join(', ')} has been granted.`,
744
- code: ErrorCode.PERMISSION_DENIED
745
- });
746
- }
747
- static evaluationFailed(options) {
748
- const error = new PermissionError({
749
- message: `The evaluation of permission ${options.name} failed.`,
750
- code: ErrorCode.PERMISSION_EVALUATION_FAILED
751
- });
752
- if (options.policy) {
753
- error.policy = options.policy;
754
- if (options.policy.type === BuiltInPolicyType.IDENTITY) {
755
- error.statusCode = 401;
756
- }
757
- }
758
- if (options.policyError) {
759
- error.policyError = options.policyError;
760
- }
761
- return error;
762
- }
763
- constructor(options = {}){
764
- super({
765
- ...options,
766
- message: options.message || 'A permission error occurred.',
767
- statusCode: options.statusCode || 403
768
- });
769
- }
770
- }
771
-
772
- /*
773
- * Copyright (c) 2025.
774
- * Author Peter Placzek (tada5hi)
775
- * For the full copyright and license information,
776
- * view the LICENSE file that was distributed with this source code.
777
- */ function buildPermissionItemKey(input) {
778
- return `${input.realmId || '_'}/${input.clientId || '_'}/${input.name}`;
779
- }
780
-
781
- /*
782
- * Copyright (c) 2024-2024.
783
- * Author Peter Placzek (tada5hi)
784
- * For the full copyright and license information,
785
- * view the LICENSE file that was distributed with this source code.
786
- */ function isPermissionItemEqual(a, b) {
787
- if (a.name !== b.name) {
788
- return false;
789
- }
790
- if (typeof a.realmId === 'string' || typeof b.realmId === 'string') {
791
- return a.realmId === b.realmId;
792
- }
793
- if (typeof a.clientId === 'string' || typeof b.clientId === 'string') {
794
- return a.clientId === b.clientId;
795
- }
796
- return !!a.realmId === !!b.realmId && !!a.clientId === !!b.clientId;
797
- }
1003
+ const PolicyDefaultEvaluators = {
1004
+ [BuiltInPolicyType.COMPOSITE]: new CompositePolicyEvaluator(),
1005
+ [BuiltInPolicyType.ATTRIBUTES]: new AttributesPolicyEvaluator(),
1006
+ [BuiltInPolicyType.ATTRIBUTE_NAMES]: new AttributeNamesPolicyEvaluator(),
1007
+ [BuiltInPolicyType.DATE]: new DatePolicyEvaluator(),
1008
+ [BuiltInPolicyType.IDENTITY]: new IdentityPolicyEvaluator(),
1009
+ [BuiltInPolicyType.PERMISSION_BINDING]: new PermissionBindingPolicyEvaluator(),
1010
+ [BuiltInPolicyType.REALM_MATCH]: new RealmMatchPolicyEvaluator(),
1011
+ [BuiltInPolicyType.TIME]: new TimePolicyEvaluator()
1012
+ };
798
1013
 
799
1014
  function mergePermissionItems(input) {
800
1015
  const grouped = input.reduce((previous, current)=>{
@@ -827,9 +1042,17 @@ function mergePermissionItems(input) {
827
1042
  return output;
828
1043
  }
829
1044
 
830
- class PermissionMemoryProvider {
831
- async get(options) {
832
- return this.items[buildPermissionItemKey(options)];
1045
+ class PermissionMemoryRepository {
1046
+ items = {};
1047
+ constructor(items = []){
1048
+ this.setMany(items);
1049
+ }
1050
+ async findOne(options) {
1051
+ const entry = this.items[buildPermissionItemKey(options)];
1052
+ if (entry) {
1053
+ return entry;
1054
+ }
1055
+ return null;
833
1056
  }
834
1057
  setMany(input) {
835
1058
  this.items = mergePermissionItems(input).reduce((prev, current)=>{
@@ -837,19 +1060,38 @@ class PermissionMemoryProvider {
837
1060
  return prev;
838
1061
  }, {});
839
1062
  }
840
- constructor(items = []){
841
- this.items = {};
842
- this.setMany(items);
843
- }
844
1063
  }
845
1064
 
846
1065
  class PermissionChecker {
1066
+ provider;
1067
+ policyEngine;
1068
+ clientId;
1069
+ realmId;
1070
+ // ----------------------------------------------
1071
+ constructor(options = {}){
1072
+ if (options.repository) {
1073
+ this.provider = options.repository;
1074
+ } else {
1075
+ this.provider = new PermissionMemoryRepository();
1076
+ }
1077
+ if (options.clientId) {
1078
+ this.clientId = options.clientId;
1079
+ }
1080
+ if (options.realmId) {
1081
+ this.realmId = options.realmId;
1082
+ }
1083
+ if (options.policyEngine) {
1084
+ this.policyEngine = options.policyEngine;
1085
+ } else {
1086
+ this.policyEngine = new PolicyEngine(PolicyDefaultEvaluators);
1087
+ }
1088
+ }
847
1089
  // ----------------------------------------------
848
1090
  /**
849
1091
  * Get a permission.
850
1092
  *
851
1093
  * @param input
852
- */ async get(input) {
1094
+ */ async findOne(input) {
853
1095
  const options = {
854
1096
  name: input
855
1097
  };
@@ -859,7 +1101,7 @@ class PermissionChecker {
859
1101
  if (this.realmId) {
860
1102
  options.realmId = this.realmId;
861
1103
  }
862
- return this.provider.get(options);
1104
+ return this.provider.findOne(options);
863
1105
  }
864
1106
  // ----------------------------------------------
865
1107
  /**
@@ -880,14 +1122,23 @@ class PermissionChecker {
880
1122
  }
881
1123
  const { options = {} } = ctx;
882
1124
  const decisionStrategy = options.decisionStrategy ?? DecisionStrategy.UNANIMOUS;
883
- let lastError;
1125
+ const issues = [];
884
1126
  let count = 0;
1127
+ const dataBase = ctx.input || new PolicyData();
885
1128
  for(let i = 0; i < ctx.name.length; i++){
886
- const entity = await this.get(ctx.name[i]);
1129
+ const entity = await this.findOne(ctx.name[i]);
887
1130
  if (!entity) {
888
- lastError = PermissionError.notFound(ctx.name[i]);
1131
+ issues.push(defineIssueItem({
1132
+ code: ErrorCode.PERMISSION_NOT_FOUND,
1133
+ message: `The ${ctx.name[i]} permission could not be resolved`,
1134
+ path: [
1135
+ ctx.name[i]
1136
+ ]
1137
+ }));
889
1138
  if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
890
- throw lastError;
1139
+ const error = PermissionError.evaluationFailed(ctx.name);
1140
+ error.addIssues(issues);
1141
+ throw error;
891
1142
  }
892
1143
  continue;
893
1144
  }
@@ -898,48 +1149,31 @@ class PermissionChecker {
898
1149
  count++;
899
1150
  continue;
900
1151
  }
901
- let outcome;
902
- try {
903
- outcome = await this.policyEngine.evaluate({
904
- input: {
905
- ...ctx.input || {},
906
- permission: entity
907
- },
908
- config: entity.policy,
909
- options: {
910
- include: options.policiesIncluded,
911
- exclude: options.policiesExcluded
912
- }
913
- });
914
- } catch (e) {
915
- if (e instanceof PolicyError) {
916
- lastError = PermissionError.evaluationFailed({
917
- name: entity.name,
918
- policy: entity.policy,
919
- policyError: e
920
- });
921
- } else {
922
- lastError = PermissionError.evaluationFailed({
923
- name: entity.name,
924
- policy: entity.policy
925
- });
926
- }
927
- outcome = false;
928
- }
929
- if (outcome) {
1152
+ const data = dataBase.clone();
1153
+ data.set(BuiltInPolicyType.PERMISSION_BINDING, entity);
1154
+ const evaluationResult = await this.policyEngine.evaluate(entity.policy, definePolicyEvaluationContext({
1155
+ include: options.policiesIncluded,
1156
+ exclude: options.policiesExcluded,
1157
+ data
1158
+ }));
1159
+ if (evaluationResult.success) {
930
1160
  if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
931
1161
  return;
932
1162
  }
933
1163
  count++;
934
1164
  } else {
935
- if (!lastError) {
936
- lastError = PermissionError.evaluationFailed({
937
- name: entity.name,
938
- policy: entity.policy
939
- });
940
- }
1165
+ issues.push(definePolicyIssueGroup({
1166
+ code: ErrorCode.PERMISSION_EVALUATION_FAILED,
1167
+ issues: evaluationResult.issues || [],
1168
+ message: `The ${entity.name} permissions policy evaluation failed`,
1169
+ path: [
1170
+ entity.name
1171
+ ]
1172
+ }));
941
1173
  if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
942
- throw lastError;
1174
+ const error = PermissionError.evaluationFailed(entity.name);
1175
+ error.addIssues(issues);
1176
+ throw error;
943
1177
  }
944
1178
  count--;
945
1179
  }
@@ -947,10 +1181,12 @@ class PermissionChecker {
947
1181
  if (count > 0) {
948
1182
  return;
949
1183
  }
950
- if (count > 1 || !lastError) {
1184
+ if (issues.length === 0) {
951
1185
  throw PermissionError.deniedAll(ctx.name);
952
1186
  } else {
953
- throw lastError;
1187
+ const error = PermissionError.evaluationFailed(ctx.name);
1188
+ error.addIssues(issues);
1189
+ throw error;
954
1190
  }
955
1191
  }
956
1192
  /**
@@ -991,26 +1227,7 @@ class PermissionChecker {
991
1227
  }
992
1228
  });
993
1229
  }
994
- // ----------------------------------------------
995
- constructor(options = {}){
996
- if (options.provider) {
997
- this.provider = options.provider;
998
- } else {
999
- this.provider = new PermissionMemoryProvider();
1000
- }
1001
- if (options.clientId) {
1002
- this.clientId = options.clientId;
1003
- }
1004
- if (options.realmId) {
1005
- this.realmId = options.realmId;
1006
- }
1007
- if (options.policyEngine) {
1008
- this.policyEngine = options.policyEngine;
1009
- } else {
1010
- this.policyEngine = new PolicyEngine();
1011
- }
1012
- }
1013
1230
  }
1014
1231
 
1015
- export { AttributeNamesPolicyEvaluator, AttributeNamesPolicyValidator, AttributesPolicyEvaluator, AttributesPolicyValidator, BuiltInPolicyType, CompositePolicyEvaluator, CompositePolicyValidator, DatePolicyEvaluator, DatePolicyValidator, DecisionStrategy, IdentityPolicyEvaluator, IdentityPolicyValidator, PermissionBindingPolicyEvaluator, PermissionBindingPolicyValidator, PermissionChecker, PermissionError, PermissionMemoryProvider, PolicyDataIdentityValidator, PolicyDataPermissionValidator, PolicyDataValidator, PolicyEngine, PolicyError, RealmMatchPolicyEvaluator, RealmMatchPolicyValidator, TimePolicyEvaluator, TimePolicyInterval, TimePolicyValidator, buildPermissionItemKey, defineAttributesPolicy, definePolicyWithType, evaluatePolicy, isCompositePolicy, isIntervalForDayOfMonth, isIntervalForDayOfWeek, isIntervalForDayOfYear, isPermissionItemEqual, maybeInvertPolicyOutcome, mergePermissionItems };
1232
+ export { AttributeNamesPolicyEvaluator, AttributeNamesPolicyValidator, AttributesPolicyEvaluator, AttributesPolicyValidator, BuiltInPolicyType, CompositePolicyEvaluator, CompositePolicyValidator, DatePolicyEvaluator, DatePolicyValidator, DecisionStrategy, IdentityPolicyEvaluator, IdentityPolicyValidator, PermissionBindingPolicyEvaluator, PermissionBindingPolicyValidator, PermissionChecker, PermissionError, PermissionMemoryRepository, PolicyData, PolicyDefaultEvaluators, PolicyEngine, PolicyError, PolicyIssueCode, PolicyIssueSeverity, RealmMatchPolicyEvaluator, RealmMatchPolicyValidator, TimePolicyEvaluator, TimePolicyInterval, TimePolicyValidator, buildPermissionItemKey, defineAttributesPolicy, definePolicyEvaluationContext, definePolicyIssueGroup, definePolicyIssueItem, definePolicyWithType, isCompositePolicy, isIntervalForDayOfMonth, isIntervalForDayOfWeek, isIntervalForDayOfYear, isPermissionItemEqual, maybeInvertPolicyOutcome, mergePermissionItems };
1016
1233
  //# sourceMappingURL=index.mjs.map