@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.
- package/README.md +24 -24
- package/dist/gate-engine-registry.js.map +1 -1
- package/dist/gate-v1-payload.schema.js +5 -0
- 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.d.ts +1 -0
- 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 -67
- 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 +557 -504
- 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
package/src/core/errors/types.ts
CHANGED
|
@@ -13,9 +13,9 @@ type ErrorSeverity = "low" | "medium" | "high" | "critical";
|
|
|
13
13
|
type JsonSafePrimitive = string | number | boolean | null;
|
|
14
14
|
|
|
15
15
|
type JsonSafeValue =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
| JsonSafePrimitive
|
|
17
|
+
| JsonSafeValue[]
|
|
18
|
+
| { [key: string]: JsonSafeValue };
|
|
19
19
|
|
|
20
20
|
type JsonSafeRecord = Record<string, JsonSafeValue>;
|
|
21
21
|
|
|
@@ -28,47 +28,47 @@ type JsonSafeRecord = Record<string, JsonSafeValue>;
|
|
|
28
28
|
* Subclasses can extend or pick from this type.
|
|
29
29
|
*/
|
|
30
30
|
type AppErrorOptions = {
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
/** Original error or exception that caused this error. */
|
|
32
|
+
cause?: unknown;
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
/** Arbitrary key-value metadata (will be sanitized to JSON-safe values). */
|
|
35
|
+
metadata?: Record<string, unknown>;
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
/** Error category/type for grouping (e.g., "authentication", "validation"). */
|
|
38
|
+
type?: string;
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
/** severity level for alerting/logging prioritization. */
|
|
41
|
+
severity?: ErrorSeverity;
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Identifies a single execution "story" in the system. All operations
|
|
45
|
+
* related to the same logical flow must share the same correlationId.
|
|
46
|
+
*/
|
|
47
|
+
correlationId?: string;
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Identifies a specific technical request attempt (each retry may produce
|
|
51
|
+
* a new requestId), even when the correlationId stays the same.
|
|
52
|
+
*/
|
|
53
|
+
requestId?: string;
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Identifies a unique business intent (idempotency key); stays the same
|
|
57
|
+
* across technical retries and multiple requests that represent the same intent.
|
|
58
|
+
*/
|
|
59
|
+
commandId?: string;
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
/** ISO timestamp of when the error was created (defaults to now). */
|
|
62
|
+
createdAtIso?: string;
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
/** Safe message that can be exposed to end users (no internal details). */
|
|
65
|
+
publicMessage?: string;
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
export type {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
AppErrorOptions,
|
|
70
|
+
ErrorSeverity,
|
|
71
|
+
JsonSafePrimitive,
|
|
72
|
+
JsonSafeRecord,
|
|
73
|
+
JsonSafeValue,
|
|
74
74
|
};
|
|
@@ -7,16 +7,16 @@ import type { AppErrorOptions } from "./types";
|
|
|
7
7
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
8
|
|
|
9
9
|
class UnexpectedError extends AppError {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
constructor(
|
|
11
|
+
message = "Unexpected error",
|
|
12
|
+
cause?: unknown,
|
|
13
|
+
options?: Omit<AppErrorOptions, "cause">,
|
|
14
|
+
) {
|
|
15
|
+
super(message, ErrorCodes.unexpected, {
|
|
16
|
+
cause,
|
|
17
|
+
...options,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export { UnexpectedError };
|
|
@@ -13,53 +13,53 @@ const NON_SERIALIZABLE_PLACEHOLDER = "[NonSerializable]";
|
|
|
13
13
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
14
14
|
|
|
15
15
|
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
if (value === null || typeof value !== "object") return false;
|
|
17
|
+
const proto = Object.getPrototypeOf(value);
|
|
18
|
+
return proto === Object.prototype || proto === null;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function sanitizeValue(value: unknown): JsonSafeValue {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
22
|
+
// Null passthrough
|
|
23
|
+
if (value === null) return null;
|
|
24
|
+
|
|
25
|
+
const type = typeof value;
|
|
26
|
+
|
|
27
|
+
// Primitives
|
|
28
|
+
if (type === "string" || type === "number" || type === "boolean") {
|
|
29
|
+
return value as JsonSafeValue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Non-serializable primitives
|
|
33
|
+
if (
|
|
34
|
+
type === "bigint" ||
|
|
35
|
+
type === "function" ||
|
|
36
|
+
type === "symbol" ||
|
|
37
|
+
value === undefined
|
|
38
|
+
) {
|
|
39
|
+
return NON_SERIALIZABLE_PLACEHOLDER;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Arrays (recursive)
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
return value.map(sanitizeValue);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Date → placeholder (could also use .toISOString() if preferred)
|
|
48
|
+
if (value instanceof Date) {
|
|
49
|
+
return NON_SERIALIZABLE_PLACEHOLDER;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Class instances and non-plain objects → placeholder
|
|
53
|
+
if (!isPlainObject(value)) {
|
|
54
|
+
return NON_SERIALIZABLE_PLACEHOLDER;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Plain object (recursive)
|
|
58
|
+
const result: Record<string, JsonSafeValue> = {};
|
|
59
|
+
for (const [key, val] of Object.entries(value)) {
|
|
60
|
+
result[key] = sanitizeValue(val);
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -77,17 +77,17 @@ function sanitizeValue(value: unknown): JsonSafeValue {
|
|
|
77
77
|
* @throws {TypeError} If `input` is not a plain object at the root level.
|
|
78
78
|
*/
|
|
79
79
|
function assertJsonSafeMetadata(input: unknown): JsonSafeRecord {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
if (input === undefined) {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
if (!isPlainObject(input)) {
|
|
85
|
+
throw new TypeError(
|
|
86
|
+
"metadata must be a plain object (Record<string, unknown>).",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
return sanitizeValue(input) as JsonSafeRecord;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
export { assertJsonSafeMetadata, NON_SERIALIZABLE_PLACEHOLDER };
|
|
@@ -10,25 +10,25 @@ import type { AppErrorOptions } from "./types";
|
|
|
10
10
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
11
|
|
|
12
12
|
class ValidationError extends AppError {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
constructor(
|
|
14
|
+
field: ValidationField,
|
|
15
|
+
code: ValidationCode,
|
|
16
|
+
message: string,
|
|
17
|
+
options?: AppErrorOptions,
|
|
18
|
+
) {
|
|
19
|
+
const baseMetadata = {
|
|
20
|
+
field: field.value,
|
|
21
|
+
validationCode: code.value,
|
|
22
|
+
};
|
|
23
|
+
const mergedMetadata = options?.metadata
|
|
24
|
+
? { ...baseMetadata, ...options.metadata }
|
|
25
|
+
: baseMetadata;
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
super(message, ErrorCodes.validation, {
|
|
28
|
+
...options,
|
|
29
|
+
metadata: mergedMetadata,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export { ValidationError };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { DomainException } from "./domain-exception";
|
|
2
2
|
|
|
3
3
|
class BusinessRuleViolationException extends DomainException {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
constructor(
|
|
5
|
+
public readonly rule: string,
|
|
6
|
+
message: string,
|
|
7
|
+
) {
|
|
8
|
+
super(message);
|
|
9
|
+
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export { BusinessRuleViolationException };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
abstract class DomainException extends Error {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
constructor(message: string) {
|
|
3
|
+
super(message);
|
|
4
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
5
|
+
this.name = new.target.name;
|
|
6
|
+
}
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export { DomainException };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { DomainException } from "./domain-exception";
|
|
2
2
|
|
|
3
3
|
class EntityNotFoundException extends DomainException {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
constructor(
|
|
5
|
+
public readonly entityName: string,
|
|
6
|
+
public readonly identifier: string,
|
|
7
|
+
) {
|
|
8
|
+
super(`${entityName} with identifier ${identifier} was not found.`);
|
|
9
|
+
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export { EntityNotFoundException };
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { DomainException } from "./domain-exception";
|
|
2
2
|
|
|
3
3
|
class InvalidStateTransitionException<
|
|
4
|
-
|
|
4
|
+
TState extends string = string,
|
|
5
5
|
> extends DomainException {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
constructor(
|
|
7
|
+
public readonly from: TState,
|
|
8
|
+
public readonly to: TState,
|
|
9
|
+
message: string,
|
|
10
|
+
) {
|
|
11
|
+
super(message);
|
|
12
|
+
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export { InvalidStateTransitionException };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DomainException } from "./domain-exception";
|
|
2
2
|
|
|
3
3
|
class InvariantViolationException extends DomainException {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
constructor(message: string) {
|
|
5
|
+
super(message);
|
|
6
|
+
}
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export { InvariantViolationException };
|
|
@@ -2,38 +2,44 @@
|
|
|
2
2
|
// Provides common reusable codes while allowing custom codes via `of`.
|
|
3
3
|
|
|
4
4
|
class ValidationCode {
|
|
5
|
-
|
|
5
|
+
public readonly value: string;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
private constructor(value: string) {
|
|
8
|
+
this.value = value;
|
|
9
|
+
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
// Factory for custom codes
|
|
12
|
+
public static of(value: string): ValidationCode {
|
|
13
|
+
return new ValidationCode(value);
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
16
|
+
// Common, domain-friendly codes
|
|
17
|
+
public static readonly BLANK = new ValidationCode("blank");
|
|
18
|
+
public static readonly REQUIRED = new ValidationCode("required");
|
|
19
|
+
public static readonly INVALID_FORMAT = new ValidationCode(
|
|
20
|
+
"invalid_format",
|
|
21
|
+
);
|
|
22
|
+
public static readonly INVALID_CHARACTERS = new ValidationCode(
|
|
23
|
+
"invalid_characters",
|
|
24
|
+
);
|
|
25
|
+
public static readonly INVALID_LENGTH = new ValidationCode(
|
|
26
|
+
"invalid_length",
|
|
27
|
+
);
|
|
28
|
+
public static readonly TOO_SHORT = new ValidationCode("too_short");
|
|
29
|
+
public static readonly TOO_LONG = new ValidationCode("too_long");
|
|
30
|
+
public static readonly OUT_OF_RANGE = new ValidationCode("out_of_range");
|
|
31
|
+
public static readonly INVALID_CHECKSUM = new ValidationCode(
|
|
32
|
+
"invalid_checksum",
|
|
33
|
+
);
|
|
34
|
+
public static readonly INVALID_CHECKING_DIGIT = new ValidationCode(
|
|
35
|
+
"invalid_checking_digit",
|
|
36
|
+
);
|
|
37
|
+
public static readonly ALREADY_EXISTS = new ValidationCode(
|
|
38
|
+
"already_exists",
|
|
39
|
+
);
|
|
40
|
+
public static readonly NOT_FOUND = new ValidationCode("not_found");
|
|
41
|
+
public static readonly NOT_ALLOWED = new ValidationCode("not_allowed");
|
|
42
|
+
public static readonly UNEXPECTED = new ValidationCode("unexpected");
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
export { ValidationCode };
|
|
@@ -3,37 +3,37 @@ import { ValidationCode } from "./validation-code";
|
|
|
3
3
|
import { ValidationField } from "./validation-field";
|
|
4
4
|
|
|
5
5
|
export interface ValidationViolation {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
readonly field: ValidationField;
|
|
7
|
+
readonly code: ValidationCode;
|
|
8
|
+
readonly message: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
class ValidationException extends DomainException {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
constructor(
|
|
13
|
+
public readonly field: ValidationField,
|
|
14
|
+
public readonly code: ValidationCode,
|
|
15
|
+
message: string,
|
|
16
|
+
) {
|
|
17
|
+
super(message);
|
|
18
|
+
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// Carries multiple validation violations from a single operation (e.g. bulk validation).
|
|
22
22
|
// Use when you need to report all field errors at once rather than failing on the first.
|
|
23
23
|
class MultipleValidationException extends DomainException {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
constructor(public readonly violations: readonly ValidationViolation[]) {
|
|
25
|
+
super(violations.map((v) => v.message).join("; "));
|
|
26
|
+
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
class InvalidValueException extends ValidationException {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
constructor(field: ValidationField, code: ValidationCode, message: string) {
|
|
31
|
+
super(field, code, message);
|
|
32
|
+
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
InvalidValueException,
|
|
37
|
+
MultipleValidationException,
|
|
38
|
+
ValidationException,
|
|
39
39
|
};
|
|
@@ -3,30 +3,31 @@
|
|
|
3
3
|
// This is a minimal base class — field catalogs are defined per domain/module.
|
|
4
4
|
|
|
5
5
|
class ValidationField {
|
|
6
|
-
|
|
6
|
+
public readonly value: string;
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
private constructor(value: string) {
|
|
9
|
+
this.value = value;
|
|
10
|
+
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
// Factory for custom or domain-specific fields
|
|
13
|
+
public static of(value: string): ValidationField {
|
|
14
|
+
return new ValidationField(value);
|
|
15
|
+
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
// Creates a nested field path: parent.nested('child') -> 'parent.child'
|
|
18
|
+
public nested(child: string | ValidationField): ValidationField {
|
|
19
|
+
const childValue =
|
|
20
|
+
child instanceof ValidationField ? child.value : child;
|
|
21
|
+
return new ValidationField(`${this.value}.${childValue}`);
|
|
22
|
+
}
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
public toString(): string {
|
|
25
|
+
return this.value;
|
|
26
|
+
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
public equals(other: ValidationField): boolean {
|
|
29
|
+
return this.value === other.value;
|
|
30
|
+
}
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
export { ValidationField };
|
package/src/core/index.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export * from "./errors";
|
|
2
2
|
export * from "./exceptions/validation-field";
|
|
3
3
|
export type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
LogPayload,
|
|
5
|
+
LoggerPort,
|
|
6
|
+
MetricLabels,
|
|
7
|
+
MetricsPort,
|
|
8
|
+
TraceAttributeValue,
|
|
9
|
+
TraceSpan,
|
|
10
|
+
TracerPort,
|
|
11
11
|
} from "./application";
|
|
12
12
|
export { mapPolicyEvaluationError } from "./application/policy-error-mapper";
|
|
13
13
|
export { Entity, type EntityState } from "./domain/entity";
|