@cullet/erp-core 1.0.2 → 1.0.4

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 (146) hide show
  1. package/README.md +24 -24
  2. package/dist/gate-engine-registry.js.map +1 -1
  3. package/dist/gate-v1-payload.schema.js +5 -0
  4. package/dist/gate-v1-payload.schema.js.map +1 -1
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/outcome.js.map +1 -1
  9. package/dist/policies/engines/v1/gate/index.d.ts +1 -0
  10. package/dist/policies/engines/v1/gate/index.js.map +1 -1
  11. package/dist/policy-service.js.map +1 -1
  12. package/dist/validation-code.js.map +1 -1
  13. package/dist/validation-error.js.map +1 -1
  14. package/dist/validation-field.js.map +1 -1
  15. package/meta.json +67 -67
  16. package/package.json +56 -56
  17. package/src/core/application/commands/command.ts +3 -3
  18. package/src/core/application/commands/requested-by.ts +60 -60
  19. package/src/core/application/index.ts +21 -21
  20. package/src/core/application/policy-error-mapper.ts +54 -54
  21. package/src/core/application/ports/index.ts +6 -6
  22. package/src/core/application/ports/logger.port.ts +4 -4
  23. package/src/core/application/ports/metrics.port.ts +3 -3
  24. package/src/core/application/ports/policy-port.ts +7 -7
  25. package/src/core/application/ports/repository.port.ts +3 -3
  26. package/src/core/application/ports/temporal-repository.port.ts +4 -4
  27. package/src/core/application/ports/tracer.port.ts +7 -7
  28. package/src/core/application/queries/query.ts +13 -13
  29. package/src/core/application/temporal/index.ts +7 -7
  30. package/src/core/application/temporal/temporal-context.ts +20 -20
  31. package/src/core/application/temporal/temporal-use-case.ts +22 -22
  32. package/src/core/application/use-case.ts +10 -10
  33. package/src/core/config/core-config.instance.ts +1 -1
  34. package/src/core/config/core-config.ts +59 -59
  35. package/src/core/config/index.ts +6 -6
  36. package/src/core/config/policy-reporter.ts +31 -31
  37. package/src/core/config/silent-policy-reporter.ts +1 -1
  38. package/src/core/domain/entity.ts +44 -44
  39. package/src/core/domain/rulesets/entity-ruleset.contracts.ts +6 -6
  40. package/src/core/domain/rulesets/ruleset-registry.ts +49 -49
  41. package/src/core/domain/rulesets/ruleset.contracts.ts +6 -6
  42. package/src/core/domain/rulesets/value-object-ruleset.contracts.ts +5 -5
  43. package/src/core/domain/temporal/index.ts +11 -11
  44. package/src/core/domain/temporal/temporal-range.ts +16 -16
  45. package/src/core/domain/temporal/temporal-snapshot.ts +24 -24
  46. package/src/core/domain/temporal/transaction-time.ts +30 -30
  47. package/src/core/domain/temporal/valid-time.ts +29 -29
  48. package/src/core/domain/value-object.ts +16 -16
  49. package/src/core/errors/app-error.ts +64 -64
  50. package/src/core/errors/authentication-error.ts +134 -134
  51. package/src/core/errors/authorization-error.ts +154 -154
  52. package/src/core/errors/business-rule-violation-error.ts +15 -15
  53. package/src/core/errors/conflict-error.ts +202 -201
  54. package/src/core/errors/error-codes.ts +48 -48
  55. package/src/core/errors/idempotency-error.ts +324 -320
  56. package/src/core/errors/index.ts +50 -50
  57. package/src/core/errors/integration-error.ts +120 -120
  58. package/src/core/errors/legacy-incompatible-error.ts +13 -13
  59. package/src/core/errors/not-found-error.ts +14 -14
  60. package/src/core/errors/serialization-error.ts +167 -167
  61. package/src/core/errors/temporal-error.ts +109 -107
  62. package/src/core/errors/types.ts +35 -35
  63. package/src/core/errors/unexpected-error.ts +10 -10
  64. package/src/core/errors/utils/index.ts +2 -2
  65. package/src/core/errors/utils/json-safe.ts +53 -53
  66. package/src/core/errors/validation-error.ts +18 -18
  67. package/src/core/exceptions/business-rule-violation-exception.ts +6 -6
  68. package/src/core/exceptions/domain-exception.ts +5 -5
  69. package/src/core/exceptions/entity-not-found-exception.ts +6 -6
  70. package/src/core/exceptions/invalid-state-transition-exception.ts +8 -8
  71. package/src/core/exceptions/invariant-violation-exception.ts +3 -3
  72. package/src/core/exceptions/validation-code.ts +35 -29
  73. package/src/core/exceptions/validation-exception.ts +19 -19
  74. package/src/core/exceptions/validation-field.ts +20 -19
  75. package/src/core/index.ts +7 -7
  76. package/src/core/policies/asof/asof.ts +47 -47
  77. package/src/core/policies/catalog/catalog.instance.ts +8 -6
  78. package/src/core/policies/catalog/index.ts +4 -4
  79. package/src/core/policies/catalog/policy-catalog-entry.ts +199 -197
  80. package/src/core/policies/catalog/policy-catalog.ts +101 -101
  81. package/src/core/policies/catalog/policy-key.ts +51 -51
  82. package/src/core/policies/context/context-builder.ts +335 -313
  83. package/src/core/policies/context/context-registry.instance.ts +9 -9
  84. package/src/core/policies/context/context-registry.ts +61 -61
  85. package/src/core/policies/context/context-resolver.ts +12 -12
  86. package/src/core/policies/context/context-seed.ts +19 -15
  87. package/src/core/policies/context/index.ts +9 -9
  88. package/src/core/policies/context/path.ts +135 -128
  89. package/src/core/policies/defs/in-memory-policy-definition-repo.ts +56 -55
  90. package/src/core/policies/defs/index.ts +10 -10
  91. package/src/core/policies/defs/policy-definition-repository.ts +3 -3
  92. package/src/core/policies/defs/policy-definition.ts +143 -142
  93. package/src/core/policies/defs/policy-scope.ts +21 -19
  94. package/src/core/policies/defs/policy-semver.ts +51 -51
  95. package/src/core/policies/engines/compute-engine-registry.ts +43 -43
  96. package/src/core/policies/engines/compute-evaluator-registry.ts +20 -20
  97. package/src/core/policies/engines/compute-registry.ts +45 -45
  98. package/src/core/policies/engines/compute-types.ts +15 -15
  99. package/src/core/policies/engines/condition-evaluator-reporter.ts +17 -17
  100. package/src/core/policies/engines/gate-engine-registry.ts +27 -25
  101. package/src/core/policies/engines/gate-types.ts +28 -28
  102. package/src/core/policies/engines/index.ts +28 -28
  103. package/src/core/policies/engines/parse-compute-payload.ts +51 -45
  104. package/src/core/policies/engines/parse-gate-payload.ts +42 -42
  105. package/src/core/policies/engines/v1/compute/compute-engine-v1.ts +39 -37
  106. package/src/core/policies/engines/v1/compute/compute-payload.schema.ts +43 -41
  107. package/src/core/policies/engines/v1/compute/index.ts +6 -6
  108. package/src/core/policies/engines/v1/compute/resolve-decision-table-v1.ts +41 -39
  109. package/src/core/policies/engines/v1/condition-evaluator.ts +557 -504
  110. package/src/core/policies/engines/v1/condition-schema.ts +35 -35
  111. package/src/core/policies/engines/v1/condition-types.ts +21 -21
  112. package/src/core/policies/engines/v1/gate/gate-engine-v1.ts +134 -130
  113. package/src/core/policies/engines/v1/gate/gate-types-v1.ts +5 -5
  114. package/src/core/policies/engines/v1/gate/gate-v1-payload.schema.ts +32 -30
  115. package/src/core/policies/engines/v1/gate/index.ts +4 -4
  116. package/src/core/policies/engines/v1/index.ts +8 -8
  117. package/src/core/policies/index.ts +72 -72
  118. package/src/core/policies/package/policy-package.ts +3 -3
  119. package/src/core/policies/policy-ids.ts +25 -25
  120. package/src/core/policies/resolver/policy-resolver.ts +34 -34
  121. package/src/core/policies/service/index.ts +6 -6
  122. package/src/core/policies/service/policy-evaluation-error.ts +141 -133
  123. package/src/core/policies/service/policy-service.ts +432 -419
  124. package/src/core/policies/utils/date.ts +3 -3
  125. package/src/core/policies/utils/hash.ts +61 -61
  126. package/src/core/result/outcome.ts +131 -126
  127. package/src/core/result/result.ts +130 -127
  128. package/src/core/shared/aggregate-version.ts +5 -5
  129. package/src/core/shared/hashing.ts +18 -18
  130. package/src/core/shared/immutable.ts +29 -29
  131. package/src/core/shared/temporal-guards.ts +9 -9
  132. package/src/core/versioning/domain-event-contracts.ts +40 -40
  133. package/src/core/versioning/version.ts +19 -19
  134. package/src/examples/rulesets/entity/order-creation-rules-v1.ts +18 -18
  135. package/src/examples/rulesets/entity/order-invariants-v1.ts +31 -29
  136. package/src/examples/rulesets/entity/order-invariants-v2.ts +12 -12
  137. package/src/examples/rulesets/entity/order.ts +127 -127
  138. package/src/examples/rulesets/value-object/cpf-rules-v1.ts +41 -39
  139. package/src/examples/rulesets/value-object/cpf-rules-v2.ts +14 -12
  140. package/src/examples/rulesets/value-object/cpf.ts +24 -24
  141. package/src/examples/rulesets/value-object/customer.ts +42 -39
  142. package/src/examples/rulesets/value-object/person-name-rules-v1.ts +27 -27
  143. package/src/examples/rulesets/value-object/person-name-rules-v2.ts +13 -13
  144. package/src/examples/rulesets/value-object/person-name.ts +29 -26
  145. package/src/index.ts +2 -2
  146. package/src/version.ts +1 -1
@@ -1,60 +1,60 @@
1
1
  // Semver without build metadata: comparisons are defined only over
2
2
  // major.minor.patch and optional pre-release identifiers (semver §11).
3
3
  export const POLICY_SEMVER_PATTERN =
4
- /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
4
+ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
5
5
 
6
6
  interface ParsedSemver {
7
- major: number;
8
- minor: number;
9
- patch: number;
10
- preRelease: string | null;
7
+ major: number;
8
+ minor: number;
9
+ patch: number;
10
+ preRelease: string | null;
11
11
  }
12
12
 
13
13
  function parseSemver(version: string): ParsedSemver {
14
- const withoutBuild = version.split("+")[0];
15
- const [core, preRelease = null] = withoutBuild.split("-") as [
16
- string,
17
- string | undefined,
18
- ];
19
- const [major, minor, patch] = core.split(".").map(Number) as [
20
- number,
21
- number,
22
- number,
23
- ];
24
- return { major, minor, patch, preRelease: preRelease ?? null };
14
+ const withoutBuild = version.split("+")[0];
15
+ const [core, preRelease = null] = withoutBuild.split("-") as [
16
+ string,
17
+ string | undefined,
18
+ ];
19
+ const [major, minor, patch] = core.split(".").map(Number) as [
20
+ number,
21
+ number,
22
+ number,
23
+ ];
24
+ return { major, minor, patch, preRelease: preRelease ?? null };
25
25
  }
26
26
 
27
27
  function comparePreRelease(a: string, b: string): number {
28
- const aIds = a.split(".");
29
- const bIds = b.split(".");
30
- const len = Math.max(aIds.length, bIds.length);
28
+ const aIds = a.split(".");
29
+ const bIds = b.split(".");
30
+ const len = Math.max(aIds.length, bIds.length);
31
31
 
32
- for (let i = 0; i < len; i++) {
33
- const ai = aIds[i];
34
- const bi = bIds[i];
32
+ for (let i = 0; i < len; i++) {
33
+ const ai = aIds[i];
34
+ const bi = bIds[i];
35
35
 
36
- // Shorter pre-release has lower precedence when prefix matches (semver §11.4.4)
37
- if (ai === undefined) return -1;
38
- if (bi === undefined) return 1;
36
+ // Shorter pre-release has lower precedence when prefix matches (semver §11.4.4)
37
+ if (ai === undefined) return -1;
38
+ if (bi === undefined) return 1;
39
39
 
40
- const aNum = Number(ai);
41
- const bNum = Number(bi);
42
- const aIsNum = !Number.isNaN(aNum);
43
- const bIsNum = !Number.isNaN(bNum);
40
+ const aNum = Number(ai);
41
+ const bNum = Number(bi);
42
+ const aIsNum = !Number.isNaN(aNum);
43
+ const bIsNum = !Number.isNaN(bNum);
44
44
 
45
- // Numeric identifiers always have lower precedence than alphanumeric (semver §11.4.1)
46
- if (aIsNum && !bIsNum) return -1;
47
- if (!aIsNum && bIsNum) return 1;
45
+ // Numeric identifiers always have lower precedence than alphanumeric (semver §11.4.1)
46
+ if (aIsNum && !bIsNum) return -1;
47
+ if (!aIsNum && bIsNum) return 1;
48
48
 
49
- if (aIsNum && bIsNum) {
50
- if (aNum !== bNum) return aNum - bNum;
51
- } else {
52
- if (ai < bi) return -1;
53
- if (ai > bi) return 1;
49
+ if (aIsNum && bIsNum) {
50
+ if (aNum !== bNum) return aNum - bNum;
51
+ } else {
52
+ if (ai < bi) return -1;
53
+ if (ai > bi) return 1;
54
+ }
54
55
  }
55
- }
56
56
 
57
- return 0;
57
+ return 0;
58
58
  }
59
59
 
60
60
  /**
@@ -65,19 +65,19 @@ function comparePreRelease(a: string, b: string): number {
65
65
  * `POLICY_SEMVER_PATTERN` validation (i.e. values stored in PolicyDefinition).
66
66
  */
67
67
  export function comparePolicySemver(a: string, b: string): number {
68
- const av = parseSemver(a);
69
- const bv = parseSemver(b);
68
+ const av = parseSemver(a);
69
+ const bv = parseSemver(b);
70
70
 
71
- if (av.major !== bv.major) return av.major - bv.major;
72
- if (av.minor !== bv.minor) return av.minor - bv.minor;
73
- if (av.patch !== bv.patch) return av.patch - bv.patch;
71
+ if (av.major !== bv.major) return av.major - bv.major;
72
+ if (av.minor !== bv.minor) return av.minor - bv.minor;
73
+ if (av.patch !== bv.patch) return av.patch - bv.patch;
74
74
 
75
- // Release > pre-release (semver §11.3)
76
- if (av.preRelease === null && bv.preRelease !== null) return 1;
77
- if (av.preRelease !== null && bv.preRelease === null) return -1;
78
- if (av.preRelease !== null && bv.preRelease !== null) {
79
- return comparePreRelease(av.preRelease, bv.preRelease);
80
- }
75
+ // Release > pre-release (semver §11.3)
76
+ if (av.preRelease === null && bv.preRelease !== null) return 1;
77
+ if (av.preRelease !== null && bv.preRelease === null) return -1;
78
+ if (av.preRelease !== null && bv.preRelease !== null) {
79
+ return comparePreRelease(av.preRelease, bv.preRelease);
80
+ }
81
81
 
82
- return 0;
82
+ return 0;
83
83
  }
@@ -6,52 +6,52 @@ import type { ComputeEvaluatorRegistry } from "./compute-evaluator-registry";
6
6
  import type { ComputeOutcome, VersionedComputeEngine } from "./compute-types";
7
7
 
8
8
  export class ComputeEngineRegistry {
9
- private readonly engines = new Map<number, VersionedComputeEngine>();
10
-
11
- register(engine: VersionedComputeEngine): void {
12
- this.engines.set(engine.version, engine);
13
- }
14
-
15
- get(version: number): VersionedComputeEngine | undefined {
16
- return this.engines.get(version);
17
- }
18
-
19
- evaluate(
20
- version: number,
21
- params: {
22
- readonly policyKey: string;
23
- readonly payloadSchemaVersion: number;
24
- readonly payload: unknown;
25
- readonly context: PolicyContext;
26
- readonly evaluators: ComputeEvaluatorRegistry;
27
- },
28
- ): Result<ComputeOutcome, string> {
29
- const engine = this.get(version);
30
- if (engine === undefined) {
31
- return Result.err(
32
- `No compute engine registered for version "${version}"`,
33
- );
34
- }
9
+ private readonly engines = new Map<number, VersionedComputeEngine>();
35
10
 
36
- const evaluator = params.evaluators.get(params.policyKey, version);
37
- if (evaluator === undefined) {
38
- return Result.err(
39
- `No compute evaluator registered for policy key "${params.policyKey}" and version "${version}"`,
40
- );
11
+ register(engine: VersionedComputeEngine): void {
12
+ this.engines.set(engine.version, engine);
41
13
  }
42
14
 
43
- const parsedPayloadResult = ComputePayloadParsers.parse(
44
- params.payloadSchemaVersion,
45
- params.payload,
46
- );
47
- if (parsedPayloadResult.isErr()) {
48
- return Result.err(parsedPayloadResult.errorOrNull()!);
15
+ get(version: number): VersionedComputeEngine | undefined {
16
+ return this.engines.get(version);
49
17
  }
50
18
 
51
- return engine.evaluate(
52
- parsedPayloadResult.getOrNull()!,
53
- params.context,
54
- evaluator,
55
- );
56
- }
19
+ evaluate(
20
+ version: number,
21
+ params: {
22
+ readonly policyKey: string;
23
+ readonly payloadSchemaVersion: number;
24
+ readonly payload: unknown;
25
+ readonly context: PolicyContext;
26
+ readonly evaluators: ComputeEvaluatorRegistry;
27
+ },
28
+ ): Result<ComputeOutcome, string> {
29
+ const engine = this.get(version);
30
+ if (engine === undefined) {
31
+ return Result.err(
32
+ `No compute engine registered for version "${version}"`,
33
+ );
34
+ }
35
+
36
+ const evaluator = params.evaluators.get(params.policyKey, version);
37
+ if (evaluator === undefined) {
38
+ return Result.err(
39
+ `No compute evaluator registered for policy key "${params.policyKey}" and version "${version}"`,
40
+ );
41
+ }
42
+
43
+ const parsedPayloadResult = ComputePayloadParsers.parse(
44
+ params.payloadSchemaVersion,
45
+ params.payload,
46
+ );
47
+ if (parsedPayloadResult.isErr()) {
48
+ return Result.err(parsedPayloadResult.errorOrNull()!);
49
+ }
50
+
51
+ return engine.evaluate(
52
+ parsedPayloadResult.getOrNull()!,
53
+ params.context,
54
+ evaluator,
55
+ );
56
+ }
57
57
  }
@@ -1,28 +1,28 @@
1
1
  import type {
2
- ComputeEvaluator,
3
- ComputeEvaluatorRegistration,
2
+ ComputeEvaluator,
3
+ ComputeEvaluatorRegistration,
4
4
  } from "./compute-types";
5
5
 
6
6
  export class ComputeEvaluatorRegistry {
7
- private readonly evaluators = new Map<string, ComputeEvaluator>();
7
+ private readonly evaluators = new Map<string, ComputeEvaluator>();
8
8
 
9
- private static toRegistryKey(policyKey: string, version: number): string {
10
- return `${policyKey}::${version}`;
11
- }
9
+ private static toRegistryKey(policyKey: string, version: number): string {
10
+ return `${policyKey}::${version}`;
11
+ }
12
12
 
13
- register(registration: ComputeEvaluatorRegistration): void {
14
- this.evaluators.set(
15
- ComputeEvaluatorRegistry.toRegistryKey(
16
- registration.policyKey,
17
- registration.version,
18
- ),
19
- registration.evaluator,
20
- );
21
- }
13
+ register(registration: ComputeEvaluatorRegistration): void {
14
+ this.evaluators.set(
15
+ ComputeEvaluatorRegistry.toRegistryKey(
16
+ registration.policyKey,
17
+ registration.version,
18
+ ),
19
+ registration.evaluator,
20
+ );
21
+ }
22
22
 
23
- get(policyKey: string, version: number): ComputeEvaluator | undefined {
24
- return this.evaluators.get(
25
- ComputeEvaluatorRegistry.toRegistryKey(policyKey, version),
26
- );
27
- }
23
+ get(policyKey: string, version: number): ComputeEvaluator | undefined {
24
+ return this.evaluators.get(
25
+ ComputeEvaluatorRegistry.toRegistryKey(policyKey, version),
26
+ );
27
+ }
28
28
  }
@@ -5,63 +5,63 @@ import { ComputeEngineRegistry } from "./compute-engine-registry";
5
5
  import { ComputeEvaluatorRegistry } from "./compute-evaluator-registry";
6
6
  import type { PolicyContext } from "./gate-types";
7
7
  import type {
8
- ComputeEvaluator,
9
- ComputeEvaluatorRegistration,
10
- ComputeOutcome,
11
- VersionedComputeEngine,
8
+ ComputeEvaluator,
9
+ ComputeEvaluatorRegistration,
10
+ ComputeOutcome,
11
+ VersionedComputeEngine,
12
12
  } from "./compute-types";
13
13
  import { ComputeEngineV1 } from "./v1/compute";
14
14
 
15
15
  export interface ComputeRegistryOptions {
16
- readonly coreConfig?: CoreConfig;
16
+ readonly coreConfig?: CoreConfig;
17
17
  }
18
18
 
19
19
  export class ComputeRegistry {
20
- private readonly engines = new ComputeEngineRegistry();
21
- private readonly evaluators = new ComputeEvaluatorRegistry();
20
+ private readonly engines = new ComputeEngineRegistry();
21
+ private readonly evaluators = new ComputeEvaluatorRegistry();
22
22
 
23
- constructor(params: ComputeRegistryOptions = {}) {
24
- const resolvedCoreConfig = params.coreConfig ?? coreConfig;
23
+ constructor(params: ComputeRegistryOptions = {}) {
24
+ const resolvedCoreConfig = params.coreConfig ?? coreConfig;
25
25
 
26
- this.engines.register(
27
- new ComputeEngineV1({
28
- coreConfig: resolvedCoreConfig,
29
- }),
30
- );
31
- }
26
+ this.engines.register(
27
+ new ComputeEngineV1({
28
+ coreConfig: resolvedCoreConfig,
29
+ }),
30
+ );
31
+ }
32
32
 
33
- register(registration: ComputeEvaluatorRegistration): void {
34
- this.evaluators.register(registration);
35
- }
33
+ register(registration: ComputeEvaluatorRegistration): void {
34
+ this.evaluators.register(registration);
35
+ }
36
36
 
37
- registerEngine(engine: VersionedComputeEngine): void {
38
- this.engines.register(engine);
39
- }
37
+ registerEngine(engine: VersionedComputeEngine): void {
38
+ this.engines.register(engine);
39
+ }
40
40
 
41
- getEngine(version: number): VersionedComputeEngine | undefined {
42
- return this.engines.get(version);
43
- }
41
+ getEngine(version: number): VersionedComputeEngine | undefined {
42
+ return this.engines.get(version);
43
+ }
44
44
 
45
- getEvaluator(
46
- policyKey: string,
47
- version: number,
48
- ): ComputeEvaluator | undefined {
49
- return this.evaluators.get(policyKey, version);
50
- }
45
+ getEvaluator(
46
+ policyKey: string,
47
+ version: number,
48
+ ): ComputeEvaluator | undefined {
49
+ return this.evaluators.get(policyKey, version);
50
+ }
51
51
 
52
- evaluate(
53
- policyKey: string,
54
- computeEngineVersion: number,
55
- payloadSchemaVersion: number,
56
- payload: unknown,
57
- context: PolicyContext,
58
- ): Result<ComputeOutcome, string> {
59
- return this.engines.evaluate(computeEngineVersion, {
60
- policyKey,
61
- payloadSchemaVersion,
62
- payload,
63
- context,
64
- evaluators: this.evaluators,
65
- });
66
- }
52
+ evaluate(
53
+ policyKey: string,
54
+ computeEngineVersion: number,
55
+ payloadSchemaVersion: number,
56
+ payload: unknown,
57
+ context: PolicyContext,
58
+ ): Result<ComputeOutcome, string> {
59
+ return this.engines.evaluate(computeEngineVersion, {
60
+ policyKey,
61
+ payloadSchemaVersion,
62
+ payload,
63
+ context,
64
+ evaluators: this.evaluators,
65
+ });
66
+ }
67
67
  }
@@ -9,8 +9,8 @@ import type { PolicyContext, PolicyViolation } from "./gate-types";
9
9
  export type ComputeStatus = "OK" | "NOT_APPLICABLE" | "ERROR";
10
10
 
11
11
  export interface ComputeOutcomeData {
12
- readonly values: unknown | null;
13
- readonly violations: readonly PolicyViolation[];
12
+ readonly values: unknown | null;
13
+ readonly violations: readonly PolicyViolation[];
14
14
  }
15
15
 
16
16
  /** Semantic outcome of a COMPUTE policy evaluation. */
@@ -29,23 +29,23 @@ export type ComputeOutcome = Outcome<ComputeStatus, ComputeOutcomeData>;
29
29
  * Outcome carries the semantic business decision.
30
30
  */
31
31
  export interface ComputeEvaluator {
32
- evaluate(
33
- resolvedValue: unknown,
34
- context: Record<string, unknown>,
35
- ): Result<ComputeOutcome, string>;
32
+ evaluate(
33
+ resolvedValue: unknown,
34
+ context: Record<string, unknown>,
35
+ ): Result<ComputeOutcome, string>;
36
36
  }
37
37
 
38
38
  export interface ComputeEvaluatorRegistration {
39
- readonly policyKey: string;
40
- readonly version: number;
41
- readonly evaluator: ComputeEvaluator;
39
+ readonly policyKey: string;
40
+ readonly version: number;
41
+ readonly evaluator: ComputeEvaluator;
42
42
  }
43
43
 
44
44
  export interface VersionedComputeEngine {
45
- readonly version: number;
46
- evaluate(
47
- payload: ComputePayload,
48
- context: PolicyContext,
49
- evaluator: ComputeEvaluator,
50
- ): Result<ComputeOutcome, string>;
45
+ readonly version: number;
46
+ evaluate(
47
+ payload: ComputePayload,
48
+ context: PolicyContext,
49
+ evaluator: ComputeEvaluator,
50
+ ): Result<ComputeOutcome, string>;
51
51
  }
@@ -1,34 +1,34 @@
1
1
  export interface ConditionEvaluationCause {
2
- readonly name: string;
3
- readonly message: string;
2
+ readonly name: string;
3
+ readonly message: string;
4
4
  }
5
5
 
6
6
  export type ConditionEvaluationReportLevel = "warn" | "error";
7
7
 
8
8
  export type ConditionEvaluationReportTag =
9
- | "MISSING_CONTEXT_FIELD"
10
- | "NULLISH_NUMERIC_OPERAND_NOT_ALLOWED"
11
- | "NULLISH_DATE_OPERAND_NOT_ALLOWED"
12
- | "INVALID_DATE_OPERAND"
13
- | "CONDITION_EVAL_THREW";
9
+ | "MISSING_CONTEXT_FIELD"
10
+ | "NULLISH_NUMERIC_OPERAND_NOT_ALLOWED"
11
+ | "NULLISH_DATE_OPERAND_NOT_ALLOWED"
12
+ | "INVALID_DATE_OPERAND"
13
+ | "CONDITION_EVAL_THREW";
14
14
 
15
15
  export interface ConditionEvaluationReport {
16
- readonly occurredAt: Date;
17
- readonly level: ConditionEvaluationReportLevel;
18
- readonly tag: ConditionEvaluationReportTag;
19
- readonly message: string;
20
- readonly engineVersion: number;
21
- readonly details: Readonly<Record<string, unknown>>;
16
+ readonly occurredAt: Date;
17
+ readonly level: ConditionEvaluationReportLevel;
18
+ readonly tag: ConditionEvaluationReportTag;
19
+ readonly message: string;
20
+ readonly engineVersion: number;
21
+ readonly details: Readonly<Record<string, unknown>>;
22
22
  }
23
23
 
24
24
  export interface ConditionEvaluatorReporter {
25
- warn(report: ConditionEvaluationReport): void;
26
- error(report: ConditionEvaluationReport): void;
25
+ warn(report: ConditionEvaluationReport): void;
26
+ error(report: ConditionEvaluationReport): void;
27
27
  }
28
28
 
29
29
  // Either fully silent (no reporter, no version stamp) or fully observable
30
30
  // (reporter paired with engineVersion so every report carries its origin).
31
31
  export type ConditionEvaluationOptions = {
32
- readonly reporter: ConditionEvaluatorReporter;
33
- readonly engineVersion: number;
32
+ readonly reporter: ConditionEvaluatorReporter;
33
+ readonly engineVersion: number;
34
34
  };
@@ -1,38 +1,40 @@
1
1
  import { Result } from "../../result/result";
2
2
 
3
3
  import type {
4
- GateOutcome,
5
- PolicyContext,
6
- VersionedGateEngine,
4
+ GateOutcome,
5
+ PolicyContext,
6
+ VersionedGateEngine,
7
7
  } from "./gate-types";
8
8
  import { GatePayloadParsers } from "./parse-gate-payload";
9
9
 
10
10
  export class GateEngineRegistry {
11
- private readonly engines = new Map<number, VersionedGateEngine>();
11
+ private readonly engines = new Map<number, VersionedGateEngine>();
12
12
 
13
- register(engine: VersionedGateEngine): void {
14
- this.engines.set(engine.version, engine);
15
- }
16
-
17
- get(version: number): VersionedGateEngine | undefined {
18
- return this.engines.get(version);
19
- }
20
-
21
- evaluate(
22
- version: number,
23
- payload: unknown,
24
- context: PolicyContext,
25
- ): Result<GateOutcome, string> {
26
- const engine = this.engines.get(version);
27
- if (!engine) {
28
- return Result.err(`No gate engine registered for version "${version}"`);
13
+ register(engine: VersionedGateEngine): void {
14
+ this.engines.set(engine.version, engine);
29
15
  }
30
16
 
31
- const parsedPayload = GatePayloadParsers.parse(version, payload);
32
- if (parsedPayload.isErr()) {
33
- return Result.err(parsedPayload.errorOrNull()!);
17
+ get(version: number): VersionedGateEngine | undefined {
18
+ return this.engines.get(version);
34
19
  }
35
20
 
36
- return engine.evaluate(parsedPayload.getOrNull()!, context);
37
- }
21
+ evaluate(
22
+ version: number,
23
+ payload: unknown,
24
+ context: PolicyContext,
25
+ ): Result<GateOutcome, string> {
26
+ const engine = this.engines.get(version);
27
+ if (!engine) {
28
+ return Result.err(
29
+ `No gate engine registered for version "${version}"`,
30
+ );
31
+ }
32
+
33
+ const parsedPayload = GatePayloadParsers.parse(version, payload);
34
+ if (parsedPayload.isErr()) {
35
+ return Result.err(parsedPayload.errorOrNull()!);
36
+ }
37
+
38
+ return engine.evaluate(parsedPayload.getOrNull()!, context);
39
+ }
38
40
  }
@@ -8,42 +8,42 @@ import type { GatePayload } from "./gate-payload";
8
8
  export type PolicyContext = Record<string, unknown>;
9
9
 
10
10
  export interface GateTraceLeafSnapshot {
11
- readonly kind: "LEAF";
12
- readonly field: string;
13
- readonly op: string;
14
- readonly allowNull?: true;
11
+ readonly kind: "LEAF";
12
+ readonly field: string;
13
+ readonly op: string;
14
+ readonly allowNull?: true;
15
15
  }
16
16
 
17
17
  export type GateTraceNodeSnapshot =
18
- | GateTraceLeafSnapshot
19
- | {
20
- readonly kind: "AND" | "OR";
21
- readonly childCount: number;
22
- }
23
- | {
24
- readonly kind: "NOT";
25
- };
18
+ | GateTraceLeafSnapshot
19
+ | {
20
+ readonly kind: "AND" | "OR";
21
+ readonly childCount: number;
22
+ }
23
+ | {
24
+ readonly kind: "NOT";
25
+ };
26
26
 
27
27
  export interface GateViolationTrace {
28
- readonly conditionPath: string;
29
- readonly decisiveNode: GateTraceNodeSnapshot;
30
- readonly lastEvaluatedLeaf: GateTraceLeafSnapshot;
31
- readonly lastEvaluatedLeafPath: string;
32
- readonly lastEvaluatedLeafResult: boolean;
33
- readonly field: string;
34
- readonly op: string;
28
+ readonly conditionPath: string;
29
+ readonly decisiveNode: GateTraceNodeSnapshot;
30
+ readonly lastEvaluatedLeaf: GateTraceLeafSnapshot;
31
+ readonly lastEvaluatedLeafPath: string;
32
+ readonly lastEvaluatedLeafResult: boolean;
33
+ readonly field: string;
34
+ readonly op: string;
35
35
  }
36
36
 
37
37
  export interface PolicyViolation {
38
- readonly code: string;
39
- readonly message: string;
40
- readonly trace?: GateViolationTrace;
38
+ readonly code: string;
39
+ readonly message: string;
40
+ readonly trace?: GateViolationTrace;
41
41
  }
42
42
 
43
43
  export type GateStatus = "ALLOW" | "DENY";
44
44
 
45
45
  export interface GateOutcomeData {
46
- readonly violations: readonly PolicyViolation[];
46
+ readonly violations: readonly PolicyViolation[];
47
47
  }
48
48
 
49
49
  /** Semantic outcome of a GATE policy evaluation. */
@@ -55,9 +55,9 @@ export type GateOutcome = Outcome<GateStatus, GateOutcomeData>;
55
55
  * the registry's responsibility via `parseGatePayload`.
56
56
  */
57
57
  export interface VersionedGateEngine {
58
- readonly version: number;
59
- evaluate(
60
- payload: GatePayload,
61
- context: PolicyContext,
62
- ): Result<GateOutcome, string>;
58
+ readonly version: number;
59
+ evaluate(
60
+ payload: GatePayload,
61
+ context: PolicyContext,
62
+ ): Result<GateOutcome, string>;
63
63
  }