@cullet/erp-core 1.0.1 → 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.
- package/README.md +24 -24
- package/dist/gate-engine-registry.js.map +1 -1
- package/dist/gate-v1-payload.schema.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/outcome.js.map +1 -1
- package/dist/policies/engines/v1/gate/index.js.map +1 -1
- package/dist/policy-service.js.map +1 -1
- package/dist/validation-code.js.map +1 -1
- package/dist/validation-error.js.map +1 -1
- package/dist/validation-field.js.map +1 -1
- package/meta.json +67 -62
- package/package.json +56 -56
- package/src/core/application/commands/command.ts +3 -3
- package/src/core/application/commands/requested-by.ts +60 -60
- package/src/core/application/index.ts +21 -21
- package/src/core/application/policy-error-mapper.ts +54 -54
- package/src/core/application/ports/index.ts +6 -6
- package/src/core/application/ports/logger.port.ts +4 -4
- package/src/core/application/ports/metrics.port.ts +3 -3
- package/src/core/application/ports/policy-port.ts +7 -7
- package/src/core/application/ports/repository.port.ts +3 -3
- package/src/core/application/ports/temporal-repository.port.ts +4 -4
- package/src/core/application/ports/tracer.port.ts +7 -7
- package/src/core/application/queries/query.ts +13 -13
- package/src/core/application/temporal/index.ts +7 -7
- package/src/core/application/temporal/temporal-context.ts +20 -20
- package/src/core/application/temporal/temporal-use-case.ts +22 -22
- package/src/core/application/use-case.ts +10 -10
- package/src/core/config/core-config.instance.ts +1 -1
- package/src/core/config/core-config.ts +59 -59
- package/src/core/config/index.ts +6 -6
- package/src/core/config/policy-reporter.ts +31 -31
- package/src/core/config/silent-policy-reporter.ts +1 -1
- package/src/core/domain/entity.ts +44 -44
- package/src/core/domain/rulesets/entity-ruleset.contracts.ts +6 -6
- package/src/core/domain/rulesets/ruleset-registry.ts +49 -49
- package/src/core/domain/rulesets/ruleset.contracts.ts +6 -6
- package/src/core/domain/rulesets/value-object-ruleset.contracts.ts +5 -5
- package/src/core/domain/temporal/index.ts +11 -11
- package/src/core/domain/temporal/temporal-range.ts +16 -16
- package/src/core/domain/temporal/temporal-snapshot.ts +24 -24
- package/src/core/domain/temporal/transaction-time.ts +30 -30
- package/src/core/domain/temporal/valid-time.ts +29 -29
- package/src/core/domain/value-object.ts +16 -16
- package/src/core/errors/app-error.ts +64 -64
- package/src/core/errors/authentication-error.ts +134 -134
- package/src/core/errors/authorization-error.ts +154 -154
- package/src/core/errors/business-rule-violation-error.ts +15 -15
- package/src/core/errors/conflict-error.ts +202 -201
- package/src/core/errors/error-codes.ts +48 -48
- package/src/core/errors/idempotency-error.ts +324 -320
- package/src/core/errors/index.ts +50 -50
- package/src/core/errors/integration-error.ts +120 -120
- package/src/core/errors/legacy-incompatible-error.ts +13 -13
- package/src/core/errors/not-found-error.ts +14 -14
- package/src/core/errors/serialization-error.ts +167 -167
- package/src/core/errors/temporal-error.ts +109 -107
- package/src/core/errors/types.ts +35 -35
- package/src/core/errors/unexpected-error.ts +10 -10
- package/src/core/errors/utils/index.ts +2 -2
- package/src/core/errors/utils/json-safe.ts +53 -53
- package/src/core/errors/validation-error.ts +18 -18
- package/src/core/exceptions/business-rule-violation-exception.ts +6 -6
- package/src/core/exceptions/domain-exception.ts +5 -5
- package/src/core/exceptions/entity-not-found-exception.ts +6 -6
- package/src/core/exceptions/invalid-state-transition-exception.ts +8 -8
- package/src/core/exceptions/invariant-violation-exception.ts +3 -3
- package/src/core/exceptions/validation-code.ts +35 -29
- package/src/core/exceptions/validation-exception.ts +19 -19
- package/src/core/exceptions/validation-field.ts +20 -19
- package/src/core/index.ts +7 -7
- package/src/core/policies/asof/asof.ts +47 -47
- package/src/core/policies/catalog/catalog.instance.ts +8 -6
- package/src/core/policies/catalog/index.ts +4 -4
- package/src/core/policies/catalog/policy-catalog-entry.ts +199 -197
- package/src/core/policies/catalog/policy-catalog.ts +101 -101
- package/src/core/policies/catalog/policy-key.ts +51 -51
- package/src/core/policies/context/context-builder.ts +335 -313
- package/src/core/policies/context/context-registry.instance.ts +9 -9
- package/src/core/policies/context/context-registry.ts +61 -61
- package/src/core/policies/context/context-resolver.ts +12 -12
- package/src/core/policies/context/context-seed.ts +19 -15
- package/src/core/policies/context/index.ts +9 -9
- package/src/core/policies/context/path.ts +135 -128
- package/src/core/policies/defs/in-memory-policy-definition-repo.ts +56 -55
- package/src/core/policies/defs/index.ts +10 -10
- package/src/core/policies/defs/policy-definition-repository.ts +3 -3
- package/src/core/policies/defs/policy-definition.ts +143 -142
- package/src/core/policies/defs/policy-scope.ts +21 -19
- package/src/core/policies/defs/policy-semver.ts +51 -51
- package/src/core/policies/engines/compute-engine-registry.ts +43 -43
- package/src/core/policies/engines/compute-evaluator-registry.ts +20 -20
- package/src/core/policies/engines/compute-registry.ts +45 -45
- package/src/core/policies/engines/compute-types.ts +15 -15
- package/src/core/policies/engines/condition-evaluator-reporter.ts +17 -17
- package/src/core/policies/engines/gate-engine-registry.ts +27 -25
- package/src/core/policies/engines/gate-types.ts +28 -28
- package/src/core/policies/engines/index.ts +28 -28
- package/src/core/policies/engines/parse-compute-payload.ts +51 -45
- package/src/core/policies/engines/parse-gate-payload.ts +42 -42
- package/src/core/policies/engines/v1/compute/compute-engine-v1.ts +39 -37
- package/src/core/policies/engines/v1/compute/compute-payload.schema.ts +43 -41
- package/src/core/policies/engines/v1/compute/index.ts +6 -6
- package/src/core/policies/engines/v1/compute/resolve-decision-table-v1.ts +41 -39
- package/src/core/policies/engines/v1/condition-evaluator.ts +547 -505
- package/src/core/policies/engines/v1/condition-schema.ts +35 -35
- package/src/core/policies/engines/v1/condition-types.ts +21 -21
- package/src/core/policies/engines/v1/gate/gate-engine-v1.ts +134 -130
- package/src/core/policies/engines/v1/gate/gate-types-v1.ts +5 -5
- package/src/core/policies/engines/v1/gate/gate-v1-payload.schema.ts +32 -30
- package/src/core/policies/engines/v1/gate/index.ts +4 -4
- package/src/core/policies/engines/v1/index.ts +8 -8
- package/src/core/policies/index.ts +72 -72
- package/src/core/policies/package/policy-package.ts +3 -3
- package/src/core/policies/policy-ids.ts +25 -25
- package/src/core/policies/resolver/policy-resolver.ts +34 -34
- package/src/core/policies/service/index.ts +6 -6
- package/src/core/policies/service/policy-evaluation-error.ts +141 -133
- package/src/core/policies/service/policy-service.ts +432 -419
- package/src/core/policies/utils/date.ts +3 -3
- package/src/core/policies/utils/hash.ts +61 -61
- package/src/core/result/outcome.ts +131 -126
- package/src/core/result/result.ts +130 -127
- package/src/core/shared/aggregate-version.ts +5 -5
- package/src/core/shared/hashing.ts +18 -18
- package/src/core/shared/immutable.ts +29 -29
- package/src/core/shared/temporal-guards.ts +9 -9
- package/src/core/versioning/domain-event-contracts.ts +40 -40
- package/src/core/versioning/version.ts +19 -19
- package/src/examples/rulesets/entity/order-creation-rules-v1.ts +18 -18
- package/src/examples/rulesets/entity/order-invariants-v1.ts +31 -29
- package/src/examples/rulesets/entity/order-invariants-v2.ts +12 -12
- package/src/examples/rulesets/entity/order.ts +127 -127
- package/src/examples/rulesets/value-object/cpf-rules-v1.ts +41 -39
- package/src/examples/rulesets/value-object/cpf-rules-v2.ts +14 -12
- package/src/examples/rulesets/value-object/cpf.ts +24 -24
- package/src/examples/rulesets/value-object/customer.ts +42 -39
- package/src/examples/rulesets/value-object/person-name-rules-v1.ts +27 -27
- package/src/examples/rulesets/value-object/person-name-rules-v2.ts +13 -13
- package/src/examples/rulesets/value-object/person-name.ts +29 -26
- package/src/index.ts +2 -2
- package/src/version.ts +1 -1
|
@@ -8,117 +8,117 @@ import { PolicyCatalogEntry } from "./policy-catalog-entry";
|
|
|
8
8
|
* The catalog defines the universe of policies; the database cannot invent new ones.
|
|
9
9
|
*/
|
|
10
10
|
export class PolicyCatalog {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
11
|
+
private readonly versionedEntries: ReadonlyMap<string, PolicyCatalogEntry>;
|
|
12
|
+
private readonly entriesByKey: ReadonlyMap<
|
|
13
|
+
string,
|
|
14
|
+
readonly PolicyCatalogEntry[]
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
constructor(entries: readonly PolicyCatalogEntry[]) {
|
|
18
|
+
const families = new Map<string, PolicyCatalogEntry[]>();
|
|
19
|
+
const versionedMap = new Map<string, PolicyCatalogEntry>();
|
|
20
|
+
|
|
21
|
+
for (const rawEntry of entries) {
|
|
22
|
+
const entry = PolicyCatalogEntry.from(rawEntry);
|
|
23
|
+
const key = entry.key.toString();
|
|
24
|
+
const variantKey = entry.toVariantKey();
|
|
25
|
+
|
|
26
|
+
if (versionedMap.has(variantKey)) {
|
|
27
|
+
throw new UnexpectedError(
|
|
28
|
+
`Duplicate PolicyCatalog entry for key "${key}" and variant "${variantKey}"`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const family = families.get(key) ?? [];
|
|
33
|
+
family.push(entry);
|
|
34
|
+
families.set(key, family);
|
|
35
|
+
versionedMap.set(variantKey, entry);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
for (const family of families.values()) {
|
|
39
|
+
PolicyCatalogEntry.assertFamilyConsistency(family);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.versionedEntries = versionedMap;
|
|
43
|
+
this.entriesByKey = families;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
get(key: string): Result<PolicyCatalogEntry, string> {
|
|
47
|
+
const familyResult = this.getFamily(key);
|
|
48
|
+
if (familyResult.isErr()) {
|
|
49
|
+
return Result.err(familyResult.errorOrNull()!);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const family = familyResult.getOrNull()!;
|
|
53
|
+
if (family.length > 1) {
|
|
54
|
+
return Result.err(
|
|
55
|
+
`Policy key "${key}" has multiple catalog variants; use getVersioned(...) or getFamily(...)`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const [entry] = family;
|
|
60
|
+
if (!entry) {
|
|
61
|
+
return Result.err(`Policy not found in catalog: "${key}"`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return Result.ok(entry);
|
|
50
65
|
}
|
|
51
66
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
67
|
+
getFamily(key: string): Result<readonly PolicyCatalogEntry[], string> {
|
|
68
|
+
const family = this.entriesByKey.get(key);
|
|
69
|
+
if (!family) {
|
|
70
|
+
return Result.err(`Policy not found in catalog: "${key}"`);
|
|
71
|
+
}
|
|
58
72
|
|
|
59
|
-
|
|
60
|
-
if (!entry) {
|
|
61
|
-
return Result.err(`Policy not found in catalog: "${key}"`);
|
|
73
|
+
return Result.ok(family);
|
|
62
74
|
}
|
|
63
75
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
getVersioned(params: {
|
|
77
|
+
readonly key: string;
|
|
78
|
+
readonly kind: "GATE" | "COMPUTE";
|
|
79
|
+
readonly gateEngineVersion?: number;
|
|
80
|
+
readonly computeEngineVersion?: number;
|
|
81
|
+
readonly payloadSchemaVersion?: number;
|
|
82
|
+
}): Result<PolicyCatalogEntry, string> {
|
|
83
|
+
const family = this.entriesByKey.get(params.key);
|
|
84
|
+
if (!family || family.length === 0) {
|
|
85
|
+
return Result.err(`Policy not found in catalog: "${params.key}"`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const exactMatch = family.find((entry) => entry.matchesVersion(params));
|
|
89
|
+
if (exactMatch) {
|
|
90
|
+
return Result.ok(exactMatch);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (family.length === 1 && !family[0].hasExplicitVersionSelector()) {
|
|
94
|
+
return Result.ok(family[0]);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const versionDetails = [
|
|
98
|
+
params.kind,
|
|
99
|
+
params.gateEngineVersion !== undefined
|
|
100
|
+
? `gateEngineVersion=${params.gateEngineVersion}`
|
|
101
|
+
: null,
|
|
102
|
+
params.computeEngineVersion !== undefined
|
|
103
|
+
? `computeEngineVersion=${params.computeEngineVersion}`
|
|
104
|
+
: null,
|
|
105
|
+
params.payloadSchemaVersion !== undefined
|
|
106
|
+
? `payloadSchemaVersion=${params.payloadSchemaVersion}`
|
|
107
|
+
: null,
|
|
108
|
+
]
|
|
109
|
+
.filter((part): part is string => part !== null)
|
|
110
|
+
.join(", ");
|
|
111
|
+
|
|
112
|
+
return Result.err(
|
|
113
|
+
`Policy variant not found in catalog: "${params.key}" (${versionDetails})`,
|
|
114
|
+
);
|
|
86
115
|
}
|
|
87
116
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return Result.ok(exactMatch);
|
|
117
|
+
list(): readonly PolicyCatalogEntry[] {
|
|
118
|
+
return Array.from(this.versionedEntries.values());
|
|
91
119
|
}
|
|
92
120
|
|
|
93
|
-
|
|
94
|
-
|
|
121
|
+
has(key: string): boolean {
|
|
122
|
+
return this.entriesByKey.has(key);
|
|
95
123
|
}
|
|
96
|
-
|
|
97
|
-
const versionDetails = [
|
|
98
|
-
params.kind,
|
|
99
|
-
params.gateEngineVersion !== undefined
|
|
100
|
-
? `gateEngineVersion=${params.gateEngineVersion}`
|
|
101
|
-
: null,
|
|
102
|
-
params.computeEngineVersion !== undefined
|
|
103
|
-
? `computeEngineVersion=${params.computeEngineVersion}`
|
|
104
|
-
: null,
|
|
105
|
-
params.payloadSchemaVersion !== undefined
|
|
106
|
-
? `payloadSchemaVersion=${params.payloadSchemaVersion}`
|
|
107
|
-
: null,
|
|
108
|
-
]
|
|
109
|
-
.filter((part): part is string => part !== null)
|
|
110
|
-
.join(", ");
|
|
111
|
-
|
|
112
|
-
return Result.err(
|
|
113
|
-
`Policy variant not found in catalog: "${params.key}" (${versionDetails})`,
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
list(): readonly PolicyCatalogEntry[] {
|
|
118
|
-
return Array.from(this.versionedEntries.values());
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
has(key: string): boolean {
|
|
122
|
-
return this.entriesByKey.has(key);
|
|
123
|
-
}
|
|
124
124
|
}
|
|
@@ -13,66 +13,66 @@ const SEGMENT_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
|
13
13
|
const MAX_POLICY_KEY_LENGTH = 255;
|
|
14
14
|
|
|
15
15
|
export class PolicyKey {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
public readonly module: string;
|
|
17
|
+
public readonly area: string;
|
|
18
|
+
public readonly name: string;
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
static parse(raw: string): Result<PolicyKey, string> {
|
|
28
|
-
if (!raw || typeof raw !== "string") {
|
|
29
|
-
return Result.err("PolicyKey cannot be empty");
|
|
20
|
+
private constructor(module: string, area: string, name: string) {
|
|
21
|
+
this.module = module;
|
|
22
|
+
this.area = area;
|
|
23
|
+
this.name = name;
|
|
24
|
+
Object.freeze(this);
|
|
30
25
|
}
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
27
|
+
static parse(raw: string): Result<PolicyKey, string> {
|
|
28
|
+
if (!raw || typeof raw !== "string") {
|
|
29
|
+
return Result.err("PolicyKey cannot be empty");
|
|
30
|
+
}
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
32
|
+
if (raw.length > MAX_POLICY_KEY_LENGTH) {
|
|
33
|
+
return Result.err(
|
|
34
|
+
`PolicyKey cannot exceed ${MAX_POLICY_KEY_LENGTH} characters, got ${raw.length}`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
44
37
|
|
|
45
|
-
|
|
38
|
+
const segments = raw.split(".");
|
|
39
|
+
if (segments.length !== 3) {
|
|
40
|
+
return Result.err(
|
|
41
|
+
`PolicyKey must have exactly 3 segments (module.area.name), got ${segments.length}: "${raw}"`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
return Result.err(
|
|
49
|
-
`PolicyKey segment "module" is invalid: "${rawModule}". ` +
|
|
50
|
-
"Must start with a lowercase letter and contain only [a-z0-9_].",
|
|
51
|
-
);
|
|
52
|
-
}
|
|
45
|
+
const [rawModule, rawArea, name] = segments;
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
47
|
+
if (!SEGMENT_PATTERN.test(rawModule)) {
|
|
48
|
+
return Result.err(
|
|
49
|
+
`PolicyKey segment "module" is invalid: "${rawModule}". ` +
|
|
50
|
+
"Must start with a lowercase letter and contain only [a-z0-9_].",
|
|
51
|
+
);
|
|
52
|
+
}
|
|
60
53
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
if (!SEGMENT_PATTERN.test(rawArea)) {
|
|
55
|
+
return Result.err(
|
|
56
|
+
`PolicyKey segment "area" is invalid: "${rawArea}". ` +
|
|
57
|
+
"Must start with a lowercase letter and contain only [a-z0-9_].",
|
|
58
|
+
);
|
|
59
|
+
}
|
|
67
60
|
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
if (!SEGMENT_PATTERN.test(name)) {
|
|
62
|
+
return Result.err(
|
|
63
|
+
`PolicyKey segment "name" is invalid: "${name}". ` +
|
|
64
|
+
"Must start with a lowercase letter and contain only [a-z0-9_].",
|
|
65
|
+
);
|
|
66
|
+
}
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
68
|
+
return Result.ok(new PolicyKey(rawModule, rawArea, name));
|
|
69
|
+
}
|
|
74
70
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
toString(): string {
|
|
72
|
+
return `${this.module}.${this.area}.${this.name}`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
equals(other: PolicyKey): boolean {
|
|
76
|
+
return this.toString() === other.toString();
|
|
77
|
+
}
|
|
78
78
|
}
|