@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,7 +1,7 @@
1
1
  import { isValidDate } from "../../shared/temporal-guards";
2
2
 
3
3
  export class PolicyDateUtils {
4
- static isValid(value: Date): boolean {
5
- return isValidDate(value);
6
- }
4
+ static isValid(value: Date): boolean {
5
+ return isValidDate(value);
6
+ }
7
7
  }
@@ -12,79 +12,79 @@ import { isValidDate } from "../../shared/temporal-guards";
12
12
  * prevent semantically different payloads from collapsing to the same hash.
13
13
  */
14
14
  export class PolicyHashing {
15
- static sha256(input: string): string {
16
- return sha256Hex(input);
17
- }
18
-
19
- private static assertHashable(value: unknown, path: string): void {
20
- if (value === null) {
21
- return;
15
+ static sha256(input: string): string {
16
+ return sha256Hex(input);
22
17
  }
23
18
 
24
- const type = typeof value;
19
+ private static assertHashable(value: unknown, path: string): void {
20
+ if (value === null) {
21
+ return;
22
+ }
25
23
 
26
- if (type === "undefined") {
27
- throw new TypeError(
28
- `canonicalJson does not accept undefined values (at ${path})`,
29
- );
30
- }
24
+ const type = typeof value;
31
25
 
32
- if (type === "number" && !Number.isFinite(value)) {
33
- throw new TypeError(
34
- `canonicalJson does not accept non-finite numbers (at ${path}, value: ${String(value)})`,
35
- );
36
- }
26
+ if (type === "undefined") {
27
+ throw new TypeError(
28
+ `canonicalJson does not accept undefined values (at ${path})`,
29
+ );
30
+ }
37
31
 
38
- if (type === "bigint" || type === "function" || type === "symbol") {
39
- throw new TypeError(
40
- `canonicalJson does not accept ${type} values (at ${path})`,
41
- );
42
- }
32
+ if (type === "number" && !Number.isFinite(value)) {
33
+ throw new TypeError(
34
+ `canonicalJson does not accept non-finite numbers (at ${path}, value: ${String(value)})`,
35
+ );
36
+ }
43
37
 
44
- if (type !== "object") {
45
- return;
46
- }
38
+ if (type === "bigint" || type === "function" || type === "symbol") {
39
+ throw new TypeError(
40
+ `canonicalJson does not accept ${type} values (at ${path})`,
41
+ );
42
+ }
47
43
 
48
- if (value instanceof Date) {
49
- if (!isValidDate(value)) {
50
- throw new TypeError(
51
- `canonicalJson does not accept Invalid Date (at ${path})`,
52
- );
53
- }
54
- return;
55
- }
44
+ if (type !== "object") {
45
+ return;
46
+ }
56
47
 
57
- if (Array.isArray(value)) {
58
- value.forEach((item, index) => {
59
- PolicyHashing.assertHashable(item, `${path}[${index}]`);
60
- });
61
- return;
62
- }
48
+ if (value instanceof Date) {
49
+ if (!isValidDate(value)) {
50
+ throw new TypeError(
51
+ `canonicalJson does not accept Invalid Date (at ${path})`,
52
+ );
53
+ }
54
+ return;
55
+ }
56
+
57
+ if (Array.isArray(value)) {
58
+ value.forEach((item, index) => {
59
+ PolicyHashing.assertHashable(item, `${path}[${index}]`);
60
+ });
61
+ return;
62
+ }
63
63
 
64
- for (const [key, nested] of Object.entries(
65
- value as Record<string, unknown>,
66
- )) {
67
- PolicyHashing.assertHashable(nested, `${path}.${key}`);
64
+ for (const [key, nested] of Object.entries(
65
+ value as Record<string, unknown>,
66
+ )) {
67
+ PolicyHashing.assertHashable(nested, `${path}.${key}`);
68
+ }
68
69
  }
69
- }
70
70
 
71
- static canonicalJson(value: unknown): string {
72
- PolicyHashing.assertHashable(value, "$");
71
+ static canonicalJson(value: unknown): string {
72
+ PolicyHashing.assertHashable(value, "$");
73
73
 
74
- return stableStringify(value);
75
- }
74
+ return stableStringify(value);
75
+ }
76
76
 
77
- static computePayloadHash(
78
- payload: unknown,
79
- policyKey: string,
80
- policyVersion: string,
81
- ): string {
82
- const canonical = PolicyHashing.canonicalJson({
83
- policyKey,
84
- policyVersion,
85
- payload,
86
- });
77
+ static computePayloadHash(
78
+ payload: unknown,
79
+ policyKey: string,
80
+ policyVersion: string,
81
+ ): string {
82
+ const canonical = PolicyHashing.canonicalJson({
83
+ policyKey,
84
+ policyVersion,
85
+ payload,
86
+ });
87
87
 
88
- return PolicyHashing.sha256(canonical);
89
- }
88
+ return PolicyHashing.sha256(canonical);
89
+ }
90
90
  }
@@ -19,140 +19,145 @@ import { InvariantViolationException } from "../exceptions/invariant-violation-e
19
19
  * @typeParam D - Shape of the decision data carried by this outcome
20
20
  */
21
21
  export class Outcome<S extends string, D = undefined> {
22
- readonly status: S;
23
- readonly data: D;
24
- readonly reason: string | undefined;
25
- readonly metadata: Readonly<Record<string, unknown>>;
26
-
27
- private constructor(
28
- status: S,
29
- data: D,
30
- reason: string | undefined,
31
- metadata: Readonly<Record<string, unknown>>,
32
- ) {
33
- this.status = status;
34
- this.data = data;
35
- this.reason = reason;
36
- this.metadata = metadata;
37
- Object.freeze(this);
38
- }
39
-
40
- // ─── Generic factory ────────────────────────────────────────────────
41
-
42
- static of<S extends string, D = undefined>(
43
- status: S,
44
- data: D,
45
- reason?: string,
46
- metadata?: Record<string, unknown>,
47
- ): Outcome<S, D> {
48
- return new Outcome(status, data, reason, Object.freeze({ ...metadata }));
49
- }
50
-
51
- // ─── Convenience factories for common business statuses ─────────────
52
-
53
- static approved<D = undefined>(
54
- data: D,
55
- reason?: string,
56
- ): Outcome<"APPROVED", D> {
57
- return new Outcome("APPROVED", data, reason, Object.freeze({}));
58
- }
59
-
60
- static rejected<D = undefined>(
61
- data: D,
62
- reason: string,
63
- ): Outcome<"REJECTED", D> {
64
- return new Outcome("REJECTED", data, reason, Object.freeze({}));
65
- }
66
-
67
- static noOp<D = undefined>(data: D, reason?: string): Outcome<"NO_OP", D> {
68
- return new Outcome("NO_OP", data, reason, Object.freeze({}));
69
- }
70
-
71
- static deferred<D = undefined>(
72
- data: D,
73
- reason: string,
74
- ): Outcome<"DEFERRED", D> {
75
- return new Outcome("DEFERRED", data, reason, Object.freeze({}));
76
- }
77
-
78
- static requiresReview<D = undefined>(
79
- data: D,
80
- reason: string,
81
- ): Outcome<"REQUIRES_REVIEW", D> {
82
- return new Outcome("REQUIRES_REVIEW", data, reason, Object.freeze({}));
83
- }
84
-
85
- // ─── Type narrowing ────────────────────────────────────────────────
86
-
87
- /**
88
- * Narrows this Outcome to a specific status.
89
- *
90
- * @example
91
- * if (outcome.is('DENY')) {
92
- * outcome.data.violations // TS knows status is 'DENY'
93
- * }
94
- */
95
- is<T extends S>(status: T): this is Outcome<T, D> {
96
- return (this.status as string) === status;
97
- }
98
-
99
- // ─── Exhaustive match ──────────────────────────────────────────────
100
-
101
- /**
102
- * Exhaustive pattern match over all possible statuses.
103
- * TypeScript enforces that every status has a handler.
104
- *
105
- * @example
106
- * outcome.match({
107
- * ALLOW: (o) => handleAllow(o.data),
108
- * DENY: (o) => handleDeny(o.data.violations),
109
- * })
110
- */
111
- match<THandlers extends { [K in S]: (outcome: Outcome<K, D>) => unknown }>(
112
- handlers: THandlers,
113
- ): ReturnType<THandlers[S]> {
114
- const handler = (
115
- handlers as Partial<Record<string, (o: unknown) => unknown>>
116
- )[this.status];
117
-
118
- if (typeof handler !== "function") {
119
- const availableStatuses = Object.keys(handlers);
120
- throw new InvariantViolationException(
121
- `Outcome.match is missing a handler for runtime status "${this.status}". Available handlers: ${availableStatuses.join(", ") || "(none)"}`,
122
- );
22
+ readonly status: S;
23
+ readonly data: D;
24
+ readonly reason: string | undefined;
25
+ readonly metadata: Readonly<Record<string, unknown>>;
26
+
27
+ private constructor(
28
+ status: S,
29
+ data: D,
30
+ reason: string | undefined,
31
+ metadata: Readonly<Record<string, unknown>>,
32
+ ) {
33
+ this.status = status;
34
+ this.data = data;
35
+ this.reason = reason;
36
+ this.metadata = metadata;
37
+ Object.freeze(this);
123
38
  }
124
39
 
125
- return handler(this) as ReturnType<THandlers[S]>;
126
- }
40
+ // ─── Generic factory ────────────────────────────────────────────────
41
+
42
+ static of<S extends string, D = undefined>(
43
+ status: S,
44
+ data: D,
45
+ reason?: string,
46
+ metadata?: Record<string, unknown>,
47
+ ): Outcome<S, D> {
48
+ return new Outcome(
49
+ status,
50
+ data,
51
+ reason,
52
+ Object.freeze({ ...metadata }),
53
+ );
54
+ }
55
+
56
+ // ─── Convenience factories for common business statuses ─────────────
57
+
58
+ static approved<D = undefined>(
59
+ data: D,
60
+ reason?: string,
61
+ ): Outcome<"APPROVED", D> {
62
+ return new Outcome("APPROVED", data, reason, Object.freeze({}));
63
+ }
64
+
65
+ static rejected<D = undefined>(
66
+ data: D,
67
+ reason: string,
68
+ ): Outcome<"REJECTED", D> {
69
+ return new Outcome("REJECTED", data, reason, Object.freeze({}));
70
+ }
127
71
 
128
- // ─── Derived copies ────────────────────────────────────────────────
72
+ static noOp<D = undefined>(data: D, reason?: string): Outcome<"NO_OP", D> {
73
+ return new Outcome("NO_OP", data, reason, Object.freeze({}));
74
+ }
129
75
 
130
- withMetadata(extra: Record<string, unknown>): Outcome<S, D> {
131
- return new Outcome(
132
- this.status,
133
- this.data,
134
- this.reason,
135
- Object.freeze({ ...this.metadata, ...extra }),
136
- );
137
- }
76
+ static deferred<D = undefined>(
77
+ data: D,
78
+ reason: string,
79
+ ): Outcome<"DEFERRED", D> {
80
+ return new Outcome("DEFERRED", data, reason, Object.freeze({}));
81
+ }
138
82
 
139
- withReason(reason: string): Outcome<S, D> {
140
- return new Outcome(this.status, this.data, reason, this.metadata);
141
- }
83
+ static requiresReview<D = undefined>(
84
+ data: D,
85
+ reason: string,
86
+ ): Outcome<"REQUIRES_REVIEW", D> {
87
+ return new Outcome("REQUIRES_REVIEW", data, reason, Object.freeze({}));
88
+ }
142
89
 
143
- // ─── Debug ─────────────────────────────────────────────────────────
90
+ // ─── Type narrowing ────────────────────────────────────────────────
91
+
92
+ /**
93
+ * Narrows this Outcome to a specific status.
94
+ *
95
+ * @example
96
+ * if (outcome.is('DENY')) {
97
+ * outcome.data.violations // TS knows status is 'DENY'
98
+ * }
99
+ */
100
+ is<T extends S>(status: T): this is Outcome<T, D> {
101
+ return (this.status as string) === status;
102
+ }
144
103
 
145
- toString(): string {
146
- const parts: string[] = [this.status];
147
- if (this.reason) parts.push(`reason="${this.reason}"`);
148
- return `Outcome(${parts.join(", ")})`;
149
- }
104
+ // ─── Exhaustive match ──────────────────────────────────────────────
105
+
106
+ /**
107
+ * Exhaustive pattern match over all possible statuses.
108
+ * TypeScript enforces that every status has a handler.
109
+ *
110
+ * @example
111
+ * outcome.match({
112
+ * ALLOW: (o) => handleAllow(o.data),
113
+ * DENY: (o) => handleDeny(o.data.violations),
114
+ * })
115
+ */
116
+ match<THandlers extends { [K in S]: (outcome: Outcome<K, D>) => unknown }>(
117
+ handlers: THandlers,
118
+ ): ReturnType<THandlers[S]> {
119
+ const handler = (
120
+ handlers as Partial<Record<string, (o: unknown) => unknown>>
121
+ )[this.status];
122
+
123
+ if (typeof handler !== "function") {
124
+ const availableStatuses = Object.keys(handlers);
125
+ throw new InvariantViolationException(
126
+ `Outcome.match is missing a handler for runtime status "${this.status}". Available handlers: ${availableStatuses.join(", ") || "(none)"}`,
127
+ );
128
+ }
129
+
130
+ return handler(this) as ReturnType<THandlers[S]>;
131
+ }
132
+
133
+ // ─── Derived copies ────────────────────────────────────────────────
134
+
135
+ withMetadata(extra: Record<string, unknown>): Outcome<S, D> {
136
+ return new Outcome(
137
+ this.status,
138
+ this.data,
139
+ this.reason,
140
+ Object.freeze({ ...this.metadata, ...extra }),
141
+ );
142
+ }
143
+
144
+ withReason(reason: string): Outcome<S, D> {
145
+ return new Outcome(this.status, this.data, reason, this.metadata);
146
+ }
147
+
148
+ // ─── Debug ─────────────────────────────────────────────────────────
149
+
150
+ toString(): string {
151
+ const parts: string[] = [this.status];
152
+ if (this.reason) parts.push(`reason="${this.reason}"`);
153
+ return `Outcome(${parts.join(", ")})`;
154
+ }
150
155
  }
151
156
 
152
157
  /** Common business outcome statuses. Extend per domain as needed. */
153
158
  export type CommonOutcomeStatus =
154
- | "APPROVED"
155
- | "REJECTED"
156
- | "NO_OP"
157
- | "DEFERRED"
158
- | "REQUIRES_REVIEW";
159
+ | "APPROVED"
160
+ | "REJECTED"
161
+ | "NO_OP"
162
+ | "DEFERRED"
163
+ | "REQUIRES_REVIEW";