@cullet/erp-core 1.0.2 → 1.0.3

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 (144) 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.map +1 -1
  4. package/dist/index.d.ts +2 -2
  5. package/dist/index.js +1 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/outcome.js.map +1 -1
  8. package/dist/policies/engines/v1/gate/index.js.map +1 -1
  9. package/dist/policy-service.js.map +1 -1
  10. package/dist/validation-code.js.map +1 -1
  11. package/dist/validation-error.js.map +1 -1
  12. package/dist/validation-field.js.map +1 -1
  13. package/meta.json +67 -67
  14. package/package.json +56 -56
  15. package/src/core/application/commands/command.ts +3 -3
  16. package/src/core/application/commands/requested-by.ts +60 -60
  17. package/src/core/application/index.ts +21 -21
  18. package/src/core/application/policy-error-mapper.ts +54 -54
  19. package/src/core/application/ports/index.ts +6 -6
  20. package/src/core/application/ports/logger.port.ts +4 -4
  21. package/src/core/application/ports/metrics.port.ts +3 -3
  22. package/src/core/application/ports/policy-port.ts +7 -7
  23. package/src/core/application/ports/repository.port.ts +3 -3
  24. package/src/core/application/ports/temporal-repository.port.ts +4 -4
  25. package/src/core/application/ports/tracer.port.ts +7 -7
  26. package/src/core/application/queries/query.ts +13 -13
  27. package/src/core/application/temporal/index.ts +7 -7
  28. package/src/core/application/temporal/temporal-context.ts +20 -20
  29. package/src/core/application/temporal/temporal-use-case.ts +22 -22
  30. package/src/core/application/use-case.ts +10 -10
  31. package/src/core/config/core-config.instance.ts +1 -1
  32. package/src/core/config/core-config.ts +59 -59
  33. package/src/core/config/index.ts +6 -6
  34. package/src/core/config/policy-reporter.ts +31 -31
  35. package/src/core/config/silent-policy-reporter.ts +1 -1
  36. package/src/core/domain/entity.ts +44 -44
  37. package/src/core/domain/rulesets/entity-ruleset.contracts.ts +6 -6
  38. package/src/core/domain/rulesets/ruleset-registry.ts +49 -49
  39. package/src/core/domain/rulesets/ruleset.contracts.ts +6 -6
  40. package/src/core/domain/rulesets/value-object-ruleset.contracts.ts +5 -5
  41. package/src/core/domain/temporal/index.ts +11 -11
  42. package/src/core/domain/temporal/temporal-range.ts +16 -16
  43. package/src/core/domain/temporal/temporal-snapshot.ts +24 -24
  44. package/src/core/domain/temporal/transaction-time.ts +30 -30
  45. package/src/core/domain/temporal/valid-time.ts +29 -29
  46. package/src/core/domain/value-object.ts +16 -16
  47. package/src/core/errors/app-error.ts +64 -64
  48. package/src/core/errors/authentication-error.ts +134 -134
  49. package/src/core/errors/authorization-error.ts +154 -154
  50. package/src/core/errors/business-rule-violation-error.ts +15 -15
  51. package/src/core/errors/conflict-error.ts +202 -201
  52. package/src/core/errors/error-codes.ts +48 -48
  53. package/src/core/errors/idempotency-error.ts +324 -320
  54. package/src/core/errors/index.ts +50 -50
  55. package/src/core/errors/integration-error.ts +120 -120
  56. package/src/core/errors/legacy-incompatible-error.ts +13 -13
  57. package/src/core/errors/not-found-error.ts +14 -14
  58. package/src/core/errors/serialization-error.ts +167 -167
  59. package/src/core/errors/temporal-error.ts +109 -107
  60. package/src/core/errors/types.ts +35 -35
  61. package/src/core/errors/unexpected-error.ts +10 -10
  62. package/src/core/errors/utils/index.ts +2 -2
  63. package/src/core/errors/utils/json-safe.ts +53 -53
  64. package/src/core/errors/validation-error.ts +18 -18
  65. package/src/core/exceptions/business-rule-violation-exception.ts +6 -6
  66. package/src/core/exceptions/domain-exception.ts +5 -5
  67. package/src/core/exceptions/entity-not-found-exception.ts +6 -6
  68. package/src/core/exceptions/invalid-state-transition-exception.ts +8 -8
  69. package/src/core/exceptions/invariant-violation-exception.ts +3 -3
  70. package/src/core/exceptions/validation-code.ts +35 -29
  71. package/src/core/exceptions/validation-exception.ts +19 -19
  72. package/src/core/exceptions/validation-field.ts +20 -19
  73. package/src/core/index.ts +7 -7
  74. package/src/core/policies/asof/asof.ts +47 -47
  75. package/src/core/policies/catalog/catalog.instance.ts +8 -6
  76. package/src/core/policies/catalog/index.ts +4 -4
  77. package/src/core/policies/catalog/policy-catalog-entry.ts +199 -197
  78. package/src/core/policies/catalog/policy-catalog.ts +101 -101
  79. package/src/core/policies/catalog/policy-key.ts +51 -51
  80. package/src/core/policies/context/context-builder.ts +335 -313
  81. package/src/core/policies/context/context-registry.instance.ts +9 -9
  82. package/src/core/policies/context/context-registry.ts +61 -61
  83. package/src/core/policies/context/context-resolver.ts +12 -12
  84. package/src/core/policies/context/context-seed.ts +19 -15
  85. package/src/core/policies/context/index.ts +9 -9
  86. package/src/core/policies/context/path.ts +135 -128
  87. package/src/core/policies/defs/in-memory-policy-definition-repo.ts +56 -55
  88. package/src/core/policies/defs/index.ts +10 -10
  89. package/src/core/policies/defs/policy-definition-repository.ts +3 -3
  90. package/src/core/policies/defs/policy-definition.ts +143 -142
  91. package/src/core/policies/defs/policy-scope.ts +21 -19
  92. package/src/core/policies/defs/policy-semver.ts +51 -51
  93. package/src/core/policies/engines/compute-engine-registry.ts +43 -43
  94. package/src/core/policies/engines/compute-evaluator-registry.ts +20 -20
  95. package/src/core/policies/engines/compute-registry.ts +45 -45
  96. package/src/core/policies/engines/compute-types.ts +15 -15
  97. package/src/core/policies/engines/condition-evaluator-reporter.ts +17 -17
  98. package/src/core/policies/engines/gate-engine-registry.ts +27 -25
  99. package/src/core/policies/engines/gate-types.ts +28 -28
  100. package/src/core/policies/engines/index.ts +28 -28
  101. package/src/core/policies/engines/parse-compute-payload.ts +51 -45
  102. package/src/core/policies/engines/parse-gate-payload.ts +42 -42
  103. package/src/core/policies/engines/v1/compute/compute-engine-v1.ts +39 -37
  104. package/src/core/policies/engines/v1/compute/compute-payload.schema.ts +43 -41
  105. package/src/core/policies/engines/v1/compute/index.ts +6 -6
  106. package/src/core/policies/engines/v1/compute/resolve-decision-table-v1.ts +41 -39
  107. package/src/core/policies/engines/v1/condition-evaluator.ts +547 -505
  108. package/src/core/policies/engines/v1/condition-schema.ts +35 -35
  109. package/src/core/policies/engines/v1/condition-types.ts +21 -21
  110. package/src/core/policies/engines/v1/gate/gate-engine-v1.ts +134 -130
  111. package/src/core/policies/engines/v1/gate/gate-types-v1.ts +5 -5
  112. package/src/core/policies/engines/v1/gate/gate-v1-payload.schema.ts +32 -30
  113. package/src/core/policies/engines/v1/gate/index.ts +4 -4
  114. package/src/core/policies/engines/v1/index.ts +8 -8
  115. package/src/core/policies/index.ts +72 -72
  116. package/src/core/policies/package/policy-package.ts +3 -3
  117. package/src/core/policies/policy-ids.ts +25 -25
  118. package/src/core/policies/resolver/policy-resolver.ts +34 -34
  119. package/src/core/policies/service/index.ts +6 -6
  120. package/src/core/policies/service/policy-evaluation-error.ts +141 -133
  121. package/src/core/policies/service/policy-service.ts +432 -419
  122. package/src/core/policies/utils/date.ts +3 -3
  123. package/src/core/policies/utils/hash.ts +61 -61
  124. package/src/core/result/outcome.ts +131 -126
  125. package/src/core/result/result.ts +130 -127
  126. package/src/core/shared/aggregate-version.ts +5 -5
  127. package/src/core/shared/hashing.ts +18 -18
  128. package/src/core/shared/immutable.ts +29 -29
  129. package/src/core/shared/temporal-guards.ts +9 -9
  130. package/src/core/versioning/domain-event-contracts.ts +40 -40
  131. package/src/core/versioning/version.ts +19 -19
  132. package/src/examples/rulesets/entity/order-creation-rules-v1.ts +18 -18
  133. package/src/examples/rulesets/entity/order-invariants-v1.ts +31 -29
  134. package/src/examples/rulesets/entity/order-invariants-v2.ts +12 -12
  135. package/src/examples/rulesets/entity/order.ts +127 -127
  136. package/src/examples/rulesets/value-object/cpf-rules-v1.ts +41 -39
  137. package/src/examples/rulesets/value-object/cpf-rules-v2.ts +14 -12
  138. package/src/examples/rulesets/value-object/cpf.ts +24 -24
  139. package/src/examples/rulesets/value-object/customer.ts +42 -39
  140. package/src/examples/rulesets/value-object/person-name-rules-v1.ts +27 -27
  141. package/src/examples/rulesets/value-object/person-name-rules-v2.ts +13 -13
  142. package/src/examples/rulesets/value-object/person-name.ts +29 -26
  143. package/src/index.ts +2 -2
  144. 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";