@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.
- 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 -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 +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
|
@@ -3,151 +3,154 @@
|
|
|
3
3
|
* Useful for avoiding excessive exceptions and making error flows explicit.
|
|
4
4
|
*/
|
|
5
5
|
export abstract class Result<T, E> {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
6
|
+
protected constructor() {
|
|
7
|
+
// prevent direct instantiation
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a success result containing a value.
|
|
12
|
+
*/
|
|
13
|
+
static ok<T>(value: T): Result<T, never> {
|
|
14
|
+
return new Ok(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates an error result containing an error object.
|
|
19
|
+
*/
|
|
20
|
+
static err<E>(error: E): Result<never, E> {
|
|
21
|
+
return new Err(error);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns true when this is a success result.
|
|
26
|
+
*/
|
|
27
|
+
abstract isOk(): this is Ok<T>;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns true when this is an error result.
|
|
31
|
+
*/
|
|
32
|
+
abstract isErr(): this is Err<E>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Runs a handler based on the result state (similar to pattern matching).
|
|
36
|
+
*/
|
|
37
|
+
abstract match<R>(handlers: {
|
|
38
|
+
ok: (value: T) => R;
|
|
39
|
+
err: (error: E) => R;
|
|
40
|
+
}): R;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Returns the value when this is success, or null when this is an error.
|
|
44
|
+
*/
|
|
45
|
+
getOrNull(): T | null {
|
|
46
|
+
return this.match({
|
|
47
|
+
ok: (value) => value,
|
|
48
|
+
err: () => null,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns the error when this is a failure, or null when this is a success.
|
|
54
|
+
*/
|
|
55
|
+
errorOrNull(): E | null {
|
|
56
|
+
return this.match({
|
|
57
|
+
ok: () => null,
|
|
58
|
+
err: (error) => error,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Returns the value when this is a success, or throws the error when this is a failure.
|
|
64
|
+
*/
|
|
65
|
+
getOrThrow(): T {
|
|
66
|
+
return this.match({
|
|
67
|
+
ok: (value) => value,
|
|
68
|
+
err: (error) => {
|
|
69
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Transforms the success value using the provided function. Keeps the error when this is a failure.
|
|
76
|
+
*/
|
|
77
|
+
map<R>(transform: (value: T) => R): Result<R, E> {
|
|
78
|
+
return this.match<Result<R, E>>({
|
|
79
|
+
ok: (value) => Result.ok(transform(value)),
|
|
80
|
+
// TS does not "see" variance here; the cast is intentional and safe:
|
|
81
|
+
// Err carries no T, so it can be widened to Result<R, E> safely.
|
|
82
|
+
err: (error) => Result.err(error) as unknown as Result<R, E>,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Transforms the error using the provided function. Keeps the value when this is a success.
|
|
88
|
+
*/
|
|
89
|
+
mapError<F>(transform: (error: E) => F): Result<T, F> {
|
|
90
|
+
return this.match<Result<T, F>>({
|
|
91
|
+
// Ok carries no E, so it can be widened to Result<T, F>.
|
|
92
|
+
ok: (value) => Result.ok(value) as unknown as Result<T, F>,
|
|
93
|
+
err: (error) => Result.err(transform(error)),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Chains another operation that returns a Result when this result is a success.
|
|
99
|
+
*/
|
|
100
|
+
flatMap<R>(transform: (value: T) => Result<R, E>): Result<R, E> {
|
|
101
|
+
return this.match<Result<R, E>>({
|
|
102
|
+
ok: (value) => transform(value),
|
|
103
|
+
err: (error) => Result.err(error) as unknown as Result<R, E>,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
/**
|
|
106
109
|
* Success variant of Result.
|
|
107
110
|
*/
|
|
108
111
|
export class Ok<T> extends Result<T, never> {
|
|
109
|
-
|
|
112
|
+
public readonly value: T;
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
constructor(value: T) {
|
|
115
|
+
super();
|
|
116
|
+
this.value = value;
|
|
117
|
+
Object.freeze(this);
|
|
118
|
+
}
|
|
116
119
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
isOk(): this is Ok<T> {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
120
123
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
isErr(): this is Err<never> {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
match<R>(handlers: { ok: (value: T) => R; err: (error: never) => R }): R {
|
|
129
|
+
return handlers.ok(this.value);
|
|
130
|
+
}
|
|
128
131
|
}
|
|
129
132
|
|
|
130
133
|
/**
|
|
131
134
|
* Error variant of Result.
|
|
132
135
|
*/
|
|
133
136
|
export class Err<E> extends Result<never, E> {
|
|
134
|
-
|
|
137
|
+
public readonly error: E;
|
|
135
138
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
constructor(error: E) {
|
|
140
|
+
super();
|
|
141
|
+
this.error = error;
|
|
142
|
+
Object.freeze(this);
|
|
143
|
+
}
|
|
141
144
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
+
isOk(): this is Ok<never> {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
145
148
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
isErr(): this is Err<E> {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
149
152
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
match<R>(handlers: { ok: (value: never) => R; err: (error: E) => R }): R {
|
|
154
|
+
return handlers.err(this.error);
|
|
155
|
+
}
|
|
153
156
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { InvariantViolationException } from "../exceptions/invariant-violation-exception";
|
|
2
2
|
|
|
3
3
|
function assertValidAggregateVersion(aggregateVersion: number): void {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
if (!Number.isInteger(aggregateVersion) || aggregateVersion < 0) {
|
|
5
|
+
throw new InvariantViolationException(
|
|
6
|
+
`aggregateVersion must be a non-negative integer. Received: ${aggregateVersion}`,
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export { assertValidAggregateVersion };
|
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
|
|
3
3
|
function sha256Hex(value: string): string {
|
|
4
|
-
|
|
4
|
+
return createHash("sha256").update(value, "utf8").digest("hex");
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
function sortKeysDeep(value: unknown): unknown {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
if (Array.isArray(value)) {
|
|
9
|
+
return value.map((item) => sortKeysDeep(item));
|
|
10
|
+
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
if (value instanceof Date) {
|
|
13
|
+
return value;
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
if (value && typeof value === "object") {
|
|
17
|
+
const record = value as Record<string, unknown>;
|
|
18
|
+
const ordered = Object.create(null) as Record<string, unknown>;
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
for (const key of Object.keys(record).sort()) {
|
|
21
|
+
ordered[key] = sortKeysDeep(record[key]);
|
|
22
|
+
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
return ordered;
|
|
25
|
+
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
return value;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function stableStringify(value: unknown): string {
|
|
31
|
-
|
|
31
|
+
return JSON.stringify(sortKeysDeep(value));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
function payloadHash(value: unknown): string {
|
|
35
|
-
|
|
35
|
+
return sha256Hex(stableStringify(value));
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export { payloadHash, sha256Hex, stableStringify };
|
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
type PrimitiveValue =
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
| bigint
|
|
3
|
+
| boolean
|
|
4
|
+
| null
|
|
5
|
+
| number
|
|
6
|
+
| string
|
|
7
|
+
| symbol
|
|
8
|
+
| undefined;
|
|
9
9
|
|
|
10
10
|
type DeepReadonly<T> = T extends PrimitiveValue | Date
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
? T
|
|
12
|
+
: T extends readonly (infer TItem)[]
|
|
13
|
+
? readonly DeepReadonly<TItem>[]
|
|
14
|
+
: { readonly [TKey in keyof T]: DeepReadonly<T[TKey]> };
|
|
15
15
|
|
|
16
16
|
function deepFreeze<T>(value: T): T {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (Array.isArray(value)) {
|
|
22
|
-
for (const item of value) {
|
|
23
|
-
deepFreeze(item);
|
|
17
|
+
if (typeof value !== "object" || value === null || value instanceof Date) {
|
|
18
|
+
return value;
|
|
24
19
|
}
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
for (const item of value) {
|
|
23
|
+
deepFreeze(item);
|
|
24
|
+
}
|
|
28
25
|
|
|
29
|
-
|
|
26
|
+
return Object.freeze(value);
|
|
27
|
+
}
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
deepFreeze(objectValue[propertyKey]);
|
|
33
|
-
}
|
|
29
|
+
const objectValue = value as Record<PropertyKey, object | PrimitiveValue>;
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
for (const propertyKey of Reflect.ownKeys(objectValue)) {
|
|
32
|
+
deepFreeze(objectValue[propertyKey]);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return Object.freeze(value);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function makeImmutable<T>(value: T): DeepReadonly<T> {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
if (typeof value !== "object" || value === null) {
|
|
40
|
+
return value as DeepReadonly<T>;
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
return deepFreeze(structuredClone(value)) as DeepReadonly<T>;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export { deepFreeze, makeImmutable, type DeepReadonly };
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { InvariantViolationException } from "../exceptions/invariant-violation-exception";
|
|
2
2
|
|
|
3
3
|
function isValidDate(value: unknown): value is Date {
|
|
4
|
-
|
|
4
|
+
return value instanceof Date && !Number.isNaN(value.getTime());
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
function cloneDate(date: Date): Date {
|
|
8
|
-
|
|
8
|
+
return new Date(date.getTime());
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
function assertValidDate(
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
fieldName: string,
|
|
13
|
+
value: unknown,
|
|
14
14
|
): asserts value is Date {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
if (!isValidDate(value)) {
|
|
16
|
+
throw new InvariantViolationException(
|
|
17
|
+
`${fieldName} must be a valid Date instance`,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export { assertValidDate, cloneDate, isValidDate };
|
|
@@ -5,69 +5,69 @@ import { assertValidAggregateVersion } from "../shared/aggregate-version";
|
|
|
5
5
|
import { type ContractVersion } from "./version";
|
|
6
6
|
|
|
7
7
|
interface DomainEventContractSelection {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
readonly entity?: boolean;
|
|
9
|
+
readonly valueObject?: boolean;
|
|
10
|
+
readonly useCase?: boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
interface DomainEventContractVersions {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
readonly entity_contract?: ContractVersion;
|
|
15
|
+
readonly value_object_contract?: ContractVersion;
|
|
16
|
+
readonly use_case_contract?: ContractVersion;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
interface CreateDomainEventEnvelopeInput<TPayload> {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
readonly aggregateVersion: number;
|
|
21
|
+
readonly payload: TPayload;
|
|
22
|
+
readonly contracts: DomainEventContractSelection;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
interface DomainEventEnvelope<TPayload> extends DomainEventContractVersions {
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
readonly aggregate_version: number;
|
|
27
|
+
readonly payload: TPayload;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function buildDomainEventContractVersions(
|
|
31
|
-
|
|
31
|
+
selection: DomainEventContractSelection,
|
|
32
32
|
): DomainEventContractVersions {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
const contractVersions: {
|
|
34
|
+
entity_contract?: ContractVersion;
|
|
35
|
+
value_object_contract?: ContractVersion;
|
|
36
|
+
use_case_contract?: ContractVersion;
|
|
37
|
+
} = {};
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
if (selection.entity) {
|
|
40
|
+
contractVersions.entity_contract = Entity.CONTRACT_VERSION;
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
if (selection.valueObject) {
|
|
44
|
+
contractVersions.value_object_contract = ValueObject.CONTRACT_VERSION;
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
if (selection.useCase) {
|
|
48
|
+
contractVersions.use_case_contract = UseCase.CONTRACT_VERSION;
|
|
49
|
+
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
return Object.freeze(contractVersions);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function createDomainEventEnvelope<TPayload>(
|
|
55
|
-
|
|
55
|
+
input: CreateDomainEventEnvelopeInput<TPayload>,
|
|
56
56
|
): DomainEventEnvelope<TPayload> {
|
|
57
|
-
|
|
57
|
+
assertValidAggregateVersion(input.aggregateVersion);
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
return Object.freeze({
|
|
60
|
+
aggregate_version: input.aggregateVersion,
|
|
61
|
+
payload: input.payload,
|
|
62
|
+
...buildDomainEventContractVersions(input.contracts),
|
|
63
|
+
});
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
buildDomainEventContractVersions,
|
|
68
|
+
createDomainEventEnvelope,
|
|
69
|
+
type CreateDomainEventEnvelopeInput,
|
|
70
|
+
type DomainEventContractSelection,
|
|
71
|
+
type DomainEventContractVersions,
|
|
72
|
+
type DomainEventEnvelope,
|
|
73
73
|
};
|
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
type ContractVersion = `${number}.${number}`;
|
|
2
2
|
|
|
3
3
|
type VersionedTarget = {
|
|
4
|
-
|
|
4
|
+
readonly prototype: object;
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
const CONTRACT_VERSION_PROPERTY = "CONTRACT_VERSION" as const;
|
|
8
8
|
const CONTRACT_VERSION_PATTERN = /^\d+\.\d+$/;
|
|
9
9
|
|
|
10
10
|
function version<const TVersion extends ContractVersion>(
|
|
11
|
-
|
|
11
|
+
contractVersion: TVersion,
|
|
12
12
|
) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
if (!CONTRACT_VERSION_PATTERN.test(contractVersion)) {
|
|
14
|
+
throw new TypeError(
|
|
15
|
+
`Invalid contract version "${contractVersion}". Expected MAJOR.MINOR.`,
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
return (target: VersionedTarget): void => {
|
|
20
|
+
Object.defineProperty(target, CONTRACT_VERSION_PROPERTY, {
|
|
21
|
+
value: contractVersion,
|
|
22
|
+
writable: false,
|
|
23
|
+
configurable: false,
|
|
24
|
+
enumerable: false,
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
CONTRACT_VERSION_PROPERTY,
|
|
31
|
+
type ContractVersion,
|
|
32
|
+
version,
|
|
33
|
+
type VersionedTarget,
|
|
34
34
|
};
|