@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
|
@@ -2,40 +2,40 @@ import { makeImmutable } from "../../shared/immutable";
|
|
|
2
2
|
import { assertValidDate } from "../../shared/temporal-guards";
|
|
3
3
|
|
|
4
4
|
interface TemporalContext {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
readonly asOf: Date;
|
|
6
|
+
readonly requestedAt: Date;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
interface CreateTemporalContextInput {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
readonly asOf?: Date;
|
|
11
|
+
readonly requestedAt?: Date;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function assertTemporalContext(
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
temporalContext: TemporalContext,
|
|
16
|
+
fieldName: string = "temporalContext",
|
|
17
17
|
): void {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
assertValidDate(`${fieldName}.asOf`, temporalContext.asOf);
|
|
19
|
+
assertValidDate(`${fieldName}.requestedAt`, temporalContext.requestedAt);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function createTemporalContext(
|
|
23
|
-
|
|
23
|
+
input: CreateTemporalContextInput = {},
|
|
24
24
|
): TemporalContext {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const requestedAt = input.requestedAt ?? new Date();
|
|
26
|
+
const asOf = input.asOf ?? requestedAt;
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
assertTemporalContext({ asOf, requestedAt });
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
return makeImmutable({
|
|
31
|
+
asOf,
|
|
32
|
+
requestedAt,
|
|
33
|
+
});
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
assertTemporalContext,
|
|
38
|
+
createTemporalContext,
|
|
39
|
+
type CreateTemporalContextInput,
|
|
40
|
+
type TemporalContext,
|
|
41
41
|
};
|
|
@@ -3,38 +3,38 @@ import type { ContextSeed } from "../../policies";
|
|
|
3
3
|
import type { Result } from "../../result/result";
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
createTemporalContext,
|
|
7
|
+
type TemporalContext,
|
|
8
8
|
} from "./temporal-context";
|
|
9
9
|
|
|
10
10
|
interface TemporalUseCaseInput {
|
|
11
|
-
|
|
11
|
+
readonly temporalContext?: TemporalContext;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
type TemporalizedContextSeed<TSeed extends ContextSeed> = TSeed;
|
|
15
15
|
|
|
16
16
|
abstract class TemporalUseCase<
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
Input extends object,
|
|
18
|
+
Output extends Result<unknown, unknown>,
|
|
19
19
|
> extends UseCase<Input & TemporalUseCaseInput, Output> {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
protected resolveTemporalContext(
|
|
21
|
+
input: Input & TemporalUseCaseInput,
|
|
22
|
+
): TemporalContext {
|
|
23
|
+
return createTemporalContext(input.temporalContext);
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
protected buildPolicySeed<TSeed extends ContextSeed>(
|
|
27
|
+
seed: TSeed,
|
|
28
|
+
temporalContext: TemporalContext,
|
|
29
|
+
): TemporalizedContextSeed<TSeed> {
|
|
30
|
+
return Object.freeze({
|
|
31
|
+
...seed,
|
|
32
|
+
fields: {
|
|
33
|
+
...seed.fields,
|
|
34
|
+
now: new Date(temporalContext.requestedAt.getTime()),
|
|
35
|
+
},
|
|
36
|
+
}) as TSeed;
|
|
37
|
+
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export type { TemporalizedContextSeed, TemporalUseCaseInput };
|
|
@@ -5,20 +5,20 @@ type MaybePromise<T> = T | Promise<T>;
|
|
|
5
5
|
|
|
6
6
|
@version("1.0")
|
|
7
7
|
abstract class UseCase<
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Input = void,
|
|
9
|
+
Output extends Result<unknown, unknown> = Result<void, never>,
|
|
10
10
|
> {
|
|
11
|
-
|
|
11
|
+
public static readonly CONTRACT_VERSION: ContractVersion;
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
public get contractVersion(): ContractVersion {
|
|
14
|
+
return UseCase.CONTRACT_VERSION;
|
|
15
|
+
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
public async run(input: Input): Promise<Output> {
|
|
18
|
+
return await this.execute(input);
|
|
19
|
+
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
protected abstract execute(input: Input): MaybePromise<Output>;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export { type MaybePromise, UseCase };
|
|
@@ -10,5 +10,5 @@ import { SilentPolicyReporter } from "./silent-policy-reporter";
|
|
|
10
10
|
* `coreConfig.configure({ observability: { reporter } })`.
|
|
11
11
|
*/
|
|
12
12
|
export const coreConfig = new CoreConfig({
|
|
13
|
-
|
|
13
|
+
observability: { reporter: new SilentPolicyReporter() },
|
|
14
14
|
});
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
ConditionEvaluationOptions,
|
|
3
|
+
ConditionEvaluatorReporter,
|
|
4
4
|
} from "../policies/engines/condition-evaluator-reporter";
|
|
5
5
|
import type { PolicyEvent, PolicyReporter } from "./policy-reporter";
|
|
6
6
|
import { SilentPolicyReporter } from "./silent-policy-reporter";
|
|
7
7
|
|
|
8
8
|
export interface CoreObservabilityConfig {
|
|
9
|
-
|
|
9
|
+
readonly reporter?: PolicyReporter;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface CoreConfigOptions {
|
|
13
|
-
|
|
13
|
+
readonly observability?: CoreObservabilityConfig;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function reportSafely(
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
policyReporter: PolicyReporter,
|
|
18
|
+
event: PolicyEvent,
|
|
19
19
|
): void {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
try {
|
|
21
|
+
policyReporter.report(event);
|
|
22
|
+
} catch {
|
|
23
|
+
// Falhas de telemetria nao podem interromper o fluxo de dominio.
|
|
24
|
+
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
@@ -29,59 +29,59 @@ function reportSafely(
|
|
|
29
29
|
* concretas de logging, tracing ou report.
|
|
30
30
|
*/
|
|
31
31
|
export class CoreConfig {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
readonly #initialReporter: PolicyReporter;
|
|
33
|
+
#currentReporter: PolicyReporter;
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
constructor(options: CoreConfigOptions = {}) {
|
|
36
|
+
const reporter =
|
|
37
|
+
options.observability?.reporter ?? new SilentPolicyReporter();
|
|
38
|
+
this.#initialReporter = reporter;
|
|
39
|
+
this.#currentReporter = reporter;
|
|
40
|
+
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
configure(options: CoreConfigOptions): this {
|
|
43
|
+
const reporter = options.observability?.reporter;
|
|
44
|
+
if (reporter) {
|
|
45
|
+
this.#currentReporter = reporter;
|
|
46
|
+
}
|
|
47
|
+
return this;
|
|
46
48
|
}
|
|
47
|
-
return this;
|
|
48
|
-
}
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
// Restores the reporter captured at construction time.
|
|
51
|
+
reset(): this {
|
|
52
|
+
this.#currentReporter = this.#initialReporter;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
getPolicyReporter(): PolicyReporter {
|
|
57
|
+
return this.#currentReporter;
|
|
58
|
+
}
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
getConditionEvaluationOptions(
|
|
61
|
+
engineVersion: number,
|
|
62
|
+
): ConditionEvaluationOptions {
|
|
63
|
+
return {
|
|
64
|
+
reporter: this.#bridgeToConditionReporter(this.#currentReporter),
|
|
65
|
+
engineVersion,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
69
|
+
#bridgeToConditionReporter(
|
|
70
|
+
policyReporter: PolicyReporter,
|
|
71
|
+
): ConditionEvaluatorReporter {
|
|
72
|
+
return {
|
|
73
|
+
warn(report) {
|
|
74
|
+
reportSafely(policyReporter, {
|
|
75
|
+
kind: "condition-eval",
|
|
76
|
+
...report,
|
|
77
|
+
} satisfies PolicyEvent);
|
|
78
|
+
},
|
|
79
|
+
error(report) {
|
|
80
|
+
reportSafely(policyReporter, {
|
|
81
|
+
kind: "condition-eval",
|
|
82
|
+
...report,
|
|
83
|
+
} satisfies PolicyEvent);
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
87
|
}
|
package/src/core/config/index.ts
CHANGED
|
@@ -2,11 +2,11 @@ export type { CoreConfigOptions, CoreObservabilityConfig } from "./core-config";
|
|
|
2
2
|
export { CoreConfig } from "./core-config";
|
|
3
3
|
export { coreConfig } from "./core-config.instance";
|
|
4
4
|
export type {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
PolicyEvent,
|
|
6
|
+
PolicyReporter,
|
|
7
|
+
ConditionEvalEvent,
|
|
8
|
+
PolicyResolutionEvent,
|
|
9
|
+
PolicyEvaluationFailedEvent,
|
|
10
|
+
PolicyEvaluationCompletedEvent,
|
|
11
11
|
} from "./policy-reporter";
|
|
12
12
|
export { SilentPolicyReporter } from "./silent-policy-reporter";
|
|
@@ -1,60 +1,60 @@
|
|
|
1
1
|
import type { ConditionEvaluationReport } from "../policies/engines/condition-evaluator-reporter";
|
|
2
2
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
PolicyDecisionId,
|
|
4
|
+
PolicyDefinitionId,
|
|
5
5
|
} from "../policies/policy-ids";
|
|
6
6
|
|
|
7
7
|
// ─── Event kinds ─────────────────────────────────────────────────────────────
|
|
8
8
|
|
|
9
9
|
export type ConditionEvalEvent = ConditionEvaluationReport & {
|
|
10
|
-
|
|
10
|
+
readonly kind: "condition-eval";
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export interface PolicyResolutionEvent {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
readonly kind: "policy-resolution";
|
|
15
|
+
readonly level: "info";
|
|
16
|
+
readonly policyKey: string;
|
|
17
|
+
readonly definitionId: PolicyDefinitionId;
|
|
18
|
+
readonly policyVersion: string;
|
|
19
|
+
readonly engineKind: "GATE" | "COMPUTE";
|
|
20
|
+
readonly engineVersion: number;
|
|
21
|
+
readonly occurredAt: Date;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export interface PolicyEvaluationFailedEvent {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
readonly kind: "policy-evaluation-failed";
|
|
26
|
+
readonly level: "error";
|
|
27
|
+
readonly policyKey: string | undefined;
|
|
28
|
+
readonly errorKind: string;
|
|
29
|
+
readonly message: string;
|
|
30
|
+
readonly cause: string;
|
|
31
|
+
readonly occurredAt: Date;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export interface PolicyEvaluationCompletedEvent {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
readonly kind: "policy-evaluation-completed";
|
|
36
|
+
readonly level: "info";
|
|
37
|
+
readonly policyKey: string;
|
|
38
|
+
readonly decisionId: PolicyDecisionId;
|
|
39
|
+
readonly engineKind: "GATE" | "COMPUTE";
|
|
40
|
+
readonly occurredAt: Date;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export type PolicyEvent =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
| ConditionEvalEvent
|
|
45
|
+
| PolicyResolutionEvent
|
|
46
|
+
| PolicyEvaluationFailedEvent
|
|
47
|
+
| PolicyEvaluationCompletedEvent;
|
|
48
48
|
|
|
49
49
|
// ─── Reporter interface ───────────────────────────────────────────────────────
|
|
50
50
|
|
|
51
51
|
export interface PolicyReporter {
|
|
52
|
-
|
|
52
|
+
report(event: PolicyEvent): void;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// ─── Re-export only what external consumers need for event construction ───────
|
|
56
56
|
|
|
57
57
|
export type {
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
ConditionEvaluationReport,
|
|
59
|
+
ConditionEvaluationReportTag,
|
|
60
60
|
} from "../policies/engines/condition-evaluator-reporter";
|
|
@@ -4,66 +4,66 @@ import { assertValidDate, cloneDate } from "../shared/temporal-guards";
|
|
|
4
4
|
import { type ContractVersion, version } from "../versioning/version";
|
|
5
5
|
|
|
6
6
|
interface EntityState<TIdentifier> {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
readonly id: TIdentifier;
|
|
8
|
+
readonly createdAt: Date;
|
|
9
|
+
readonly updatedAt: Date;
|
|
10
|
+
readonly aggregateVersion: number;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
@version("1.0")
|
|
14
14
|
abstract class Entity<TIdentifier> {
|
|
15
|
-
|
|
15
|
+
public static readonly CONTRACT_VERSION: ContractVersion;
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
private readonly _id: TIdentifier;
|
|
18
|
+
private readonly _createdAt: Date;
|
|
19
|
+
private _updatedAt: Date;
|
|
20
|
+
private _aggregateVersion: number;
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
protected constructor(state: EntityState<TIdentifier>) {
|
|
23
|
+
assertValidDate("createdAt", state.createdAt);
|
|
24
|
+
assertValidDate("updatedAt", state.updatedAt);
|
|
25
|
+
assertValidAggregateVersion(state.aggregateVersion);
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
if (state.updatedAt.getTime() < state.createdAt.getTime()) {
|
|
28
|
+
throw new InvariantViolationException(
|
|
29
|
+
"updatedAt cannot be earlier than createdAt",
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
this._id = state.id;
|
|
34
|
+
this._createdAt = cloneDate(state.createdAt);
|
|
35
|
+
this._updatedAt = cloneDate(state.updatedAt);
|
|
36
|
+
this._aggregateVersion = state.aggregateVersion;
|
|
37
|
+
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
public get id(): TIdentifier {
|
|
40
|
+
return this._id;
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
public get createdAt(): Date {
|
|
44
|
+
return cloneDate(this._createdAt);
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
public get updatedAt(): Date {
|
|
48
|
+
return cloneDate(this._updatedAt);
|
|
49
|
+
}
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
public get aggregateVersion(): number {
|
|
52
|
+
return this._aggregateVersion;
|
|
53
|
+
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
public get contractVersion(): ContractVersion {
|
|
56
|
+
return Entity.CONTRACT_VERSION;
|
|
57
|
+
}
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
protected markAsModified(updatedAt: Date = new Date()): number {
|
|
60
|
+
assertValidDate("updatedAt", updatedAt);
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
this._updatedAt = cloneDate(updatedAt);
|
|
63
|
+
this._aggregateVersion += 1;
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
return this._aggregateVersion;
|
|
66
|
+
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export { Entity, type EntityState };
|
|
@@ -2,15 +2,15 @@ import { type Ruleset, type RulesetId } from "./ruleset.contracts";
|
|
|
2
2
|
import { DomainException } from "../../exceptions/domain-exception";
|
|
3
3
|
|
|
4
4
|
interface CreationRuleset<TData> extends Ruleset {
|
|
5
|
-
|
|
5
|
+
validate(data: TData): void;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
type InvariantRuleset = Ruleset;
|
|
9
9
|
|
|
10
10
|
export {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
type CreationRuleset,
|
|
12
|
+
DomainException,
|
|
13
|
+
type InvariantRuleset,
|
|
14
|
+
type Ruleset,
|
|
15
|
+
type RulesetId,
|
|
16
16
|
};
|