@cullet/erp-core 1.3.0 → 1.4.0
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/KIT_CONTEXT.md +5 -3
- package/README.md +160 -0
- package/dist/abac/index.cjs +7 -0
- package/dist/abac/index.d.cts +2 -0
- package/dist/abac/index.d.ts +2 -0
- package/dist/abac/index.js +2 -0
- package/dist/app-error.cjs +193 -0
- package/dist/app-error.cjs.map +1 -0
- package/dist/app-error.js +170 -0
- package/dist/app-error.js.map +1 -0
- package/dist/application/index.cjs +2 -1
- package/dist/application/index.d.cts +2 -1
- package/dist/application/index.d.ts +2 -1
- package/dist/application/index.js +2 -1
- package/dist/authorization-error.cjs +157 -0
- package/dist/authorization-error.cjs.map +1 -0
- package/dist/authorization-error.d.cts +113 -0
- package/dist/authorization-error.d.ts +113 -0
- package/dist/authorization-error.js +152 -0
- package/dist/authorization-error.js.map +1 -0
- package/dist/authorizer.port.d.cts +130 -0
- package/dist/authorizer.port.d.ts +130 -0
- package/dist/composite-authorizer.d.cts +216 -0
- package/dist/composite-authorizer.d.ts +216 -0
- package/dist/condition-evaluator.cjs +565 -0
- package/dist/condition-evaluator.cjs.map +1 -0
- package/dist/condition-evaluator.js +536 -0
- package/dist/condition-evaluator.js.map +1 -0
- package/dist/{gate-types.d.ts → core-config.d.cts} +78 -77
- package/dist/{gate-types.d.cts → core-config.d.ts} +78 -77
- package/dist/domain/index.cjs +2 -1
- package/dist/domain/index.d.cts +2 -1
- package/dist/domain/index.d.ts +2 -1
- package/dist/domain/index.js +2 -1
- package/dist/domain-event-contracts.cjs +3 -2
- package/dist/domain-event-contracts.cjs.map +1 -1
- package/dist/domain-event-contracts.js +2 -1
- package/dist/domain-event-contracts.js.map +1 -1
- package/dist/entity.cjs +126 -0
- package/dist/entity.cjs.map +1 -0
- package/dist/entity.js +115 -0
- package/dist/entity.js.map +1 -0
- package/dist/errors/index.cjs +8 -6
- package/dist/errors/index.d.cts +2 -1
- package/dist/errors/index.d.ts +2 -1
- package/dist/errors/index.js +4 -2
- package/dist/gate-engine-registry.cjs +5 -4
- package/dist/gate-engine-registry.cjs.map +1 -1
- package/dist/gate-engine-registry.d.cts +3 -2
- package/dist/gate-engine-registry.d.ts +3 -2
- package/dist/gate-engine-registry.js +2 -1
- package/dist/gate-engine-registry.js.map +1 -1
- package/dist/gate-v1-payload.schema.cjs +0 -562
- package/dist/gate-v1-payload.schema.cjs.map +1 -1
- package/dist/gate-v1-payload.schema.js +1 -533
- package/dist/gate-v1-payload.schema.js.map +1 -1
- package/dist/index.cjs +34 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -12
- package/dist/index.d.ts +19 -12
- package/dist/index.js +15 -9
- package/dist/index.js.map +1 -1
- package/dist/not-found-error.cjs +5 -5
- package/dist/not-found-error.cjs.map +1 -1
- package/dist/not-found-error.js +1 -1
- package/dist/outcome.d.cts +1 -83
- package/dist/outcome.d.ts +1 -83
- package/dist/parse-gate-payload.d.cts +2 -2
- package/dist/parse-gate-payload.d.ts +2 -2
- package/dist/path.d.cts +2 -2
- package/dist/path.d.ts +2 -2
- package/dist/policies/engines/index.d.cts +1 -1
- package/dist/policies/engines/index.d.ts +1 -1
- package/dist/policies/engines/v1/gate/index.cjs +5 -4
- package/dist/policies/engines/v1/gate/index.cjs.map +1 -1
- package/dist/policies/engines/v1/gate/index.d.cts +2 -2
- package/dist/policies/engines/v1/gate/index.d.ts +2 -2
- package/dist/policies/engines/v1/gate/index.js +2 -1
- package/dist/policies/engines/v1/gate/index.js.map +1 -1
- package/dist/policies/index.cjs +5 -5
- package/dist/policies/index.d.cts +3 -2
- package/dist/policies/index.d.ts +3 -2
- package/dist/policies/index.js +2 -2
- package/dist/policy-bridge.cjs +437 -0
- package/dist/policy-bridge.cjs.map +1 -0
- package/dist/policy-bridge.d.cts +185 -0
- package/dist/policy-bridge.d.ts +185 -0
- package/dist/policy-bridge.js +396 -0
- package/dist/policy-bridge.js.map +1 -0
- package/dist/policy-service.cjs +239 -239
- package/dist/policy-service.cjs.map +1 -1
- package/dist/policy-service.d.cts +2 -2
- package/dist/policy-service.d.ts +2 -2
- package/dist/policy-service.js +239 -239
- package/dist/policy-service.js.map +1 -1
- package/dist/rbac/index.cjs +9 -0
- package/dist/rbac/index.d.cts +3 -0
- package/dist/rbac/index.d.ts +3 -0
- package/dist/rbac/index.js +2 -0
- package/dist/requested-by.cjs +54 -0
- package/dist/requested-by.cjs.map +1 -0
- package/dist/requested-by.d.cts +25 -0
- package/dist/requested-by.d.ts +25 -0
- package/dist/requested-by.js +49 -0
- package/dist/requested-by.js.map +1 -0
- package/dist/result/index.d.cts +2 -1
- package/dist/result/index.d.ts +2 -1
- package/dist/result.d.cts +84 -0
- package/dist/result.d.ts +84 -0
- package/dist/rule.cjs +327 -0
- package/dist/rule.cjs.map +1 -0
- package/dist/rule.js +298 -0
- package/dist/rule.js.map +1 -0
- package/dist/temporal-use-case.cjs +1 -53
- package/dist/temporal-use-case.cjs.map +1 -1
- package/dist/temporal-use-case.d.cts +5 -27
- package/dist/temporal-use-case.d.ts +5 -27
- package/dist/temporal-use-case.js +2 -48
- package/dist/temporal-use-case.js.map +1 -1
- package/dist/unexpected-error.cjs +3 -192
- package/dist/unexpected-error.cjs.map +1 -1
- package/dist/unexpected-error.js +2 -167
- package/dist/unexpected-error.js.map +1 -1
- package/dist/uuid-identifier.d.cts +2 -85
- package/dist/uuid-identifier.d.ts +2 -85
- package/dist/validation-error.cjs +33 -166
- package/dist/validation-error.cjs.map +1 -1
- package/dist/validation-error.d.cts +2 -98
- package/dist/validation-error.d.ts +2 -98
- package/dist/validation-error.js +7 -134
- package/dist/validation-error.js.map +1 -1
- package/dist/value-object.cjs +0 -123
- package/dist/value-object.cjs.map +1 -1
- package/dist/value-object.d.cts +89 -0
- package/dist/value-object.d.ts +89 -0
- package/dist/value-object.js +1 -112
- package/dist/value-object.js.map +1 -1
- package/meta.json +18 -4
- package/package.json +27 -1
- package/src/abac/index.ts +1 -0
- package/src/core/abac/abac-request.ts +29 -0
- package/src/core/abac/attributes.ts +39 -0
- package/src/core/abac/authorizer.ts +108 -0
- package/src/core/abac/combining.ts +63 -0
- package/src/core/abac/composite-authorizer.ts +45 -0
- package/src/core/abac/domain/policy-set.ts +52 -0
- package/src/core/abac/domain/rule.ts +197 -0
- package/src/core/abac/index.ts +21 -0
- package/src/core/application/ports/abac-authorizer.port.ts +20 -0
- package/src/core/application/ports/authorizer.port.ts +22 -0
- package/src/core/errors/authorization-error.ts +26 -0
- package/src/core/errors/error-codes.ts +1 -0
- package/src/core/index.ts +7 -0
- package/src/core/rbac/access-request.ts +32 -0
- package/src/core/rbac/authorizer.ts +91 -0
- package/src/core/rbac/domain/grant.ts +96 -0
- package/src/core/rbac/domain/permission-set.ts +67 -0
- package/src/core/rbac/domain/permission.ts +119 -0
- package/src/core/rbac/domain/role.ts +101 -0
- package/src/core/rbac/domain/scope.ts +84 -0
- package/src/core/rbac/index.ts +15 -0
- package/src/core/rbac/policy-bridge.ts +44 -0
- package/src/examples/application/authorize-cancel-order-abac.example.ts +107 -0
- package/src/examples/application/authorize-cancel-order.example.ts +101 -0
- package/src/rbac/index.ts +1 -0
- package/src/version.ts +1 -1
|
@@ -1,5 +1,80 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as Result } from "./result.cjs";
|
|
2
|
+
import { n as Outcome } from "./outcome.cjs";
|
|
2
3
|
|
|
4
|
+
//#region src/core/policies/engines/v1/condition-types.d.ts
|
|
5
|
+
type ConditionOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "isNull" | "isNotNull";
|
|
6
|
+
interface ConditionLeafNode {
|
|
7
|
+
readonly field: string;
|
|
8
|
+
readonly op: ConditionOp;
|
|
9
|
+
readonly value: unknown;
|
|
10
|
+
readonly allowNull?: true;
|
|
11
|
+
}
|
|
12
|
+
interface ConditionAndNode {
|
|
13
|
+
readonly and: readonly ConditionNode[];
|
|
14
|
+
}
|
|
15
|
+
interface ConditionOrNode {
|
|
16
|
+
readonly or: readonly ConditionNode[];
|
|
17
|
+
}
|
|
18
|
+
interface ConditionNotNode {
|
|
19
|
+
readonly not: ConditionNode;
|
|
20
|
+
}
|
|
21
|
+
type ConditionNode = ConditionLeafNode | ConditionAndNode | ConditionOrNode | ConditionNotNode;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/core/policies/engines/v1/gate/gate-types-v1.d.ts
|
|
24
|
+
type GatePayloadV1 = {
|
|
25
|
+
readonly condition: ConditionNode;
|
|
26
|
+
} | {
|
|
27
|
+
readonly allowIf: ConditionNode;
|
|
28
|
+
readonly defaultOutcome: "ALLOW" | "DENY";
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/core/policies/engines/gate-payload.d.ts
|
|
32
|
+
type GatePayload = GatePayloadV1;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/core/policies/engines/gate-types.d.ts
|
|
35
|
+
type PolicyContext = Record<string, unknown>;
|
|
36
|
+
interface GateTraceLeafSnapshot {
|
|
37
|
+
readonly kind: "LEAF";
|
|
38
|
+
readonly field: string;
|
|
39
|
+
readonly op: string;
|
|
40
|
+
readonly allowNull?: true;
|
|
41
|
+
}
|
|
42
|
+
type GateTraceNodeSnapshot = GateTraceLeafSnapshot | {
|
|
43
|
+
readonly kind: "AND" | "OR";
|
|
44
|
+
readonly childCount: number;
|
|
45
|
+
} | {
|
|
46
|
+
readonly kind: "NOT";
|
|
47
|
+
};
|
|
48
|
+
interface GateViolationTrace {
|
|
49
|
+
readonly conditionPath: string;
|
|
50
|
+
readonly decisiveNode: GateTraceNodeSnapshot;
|
|
51
|
+
readonly lastEvaluatedLeaf: GateTraceLeafSnapshot;
|
|
52
|
+
readonly lastEvaluatedLeafPath: string;
|
|
53
|
+
readonly lastEvaluatedLeafResult: boolean;
|
|
54
|
+
readonly field: string;
|
|
55
|
+
readonly op: string;
|
|
56
|
+
}
|
|
57
|
+
interface PolicyViolation {
|
|
58
|
+
readonly code: string;
|
|
59
|
+
readonly message: string;
|
|
60
|
+
readonly trace?: GateViolationTrace;
|
|
61
|
+
}
|
|
62
|
+
type GateStatus = "ALLOW" | "DENY";
|
|
63
|
+
interface GateOutcomeData {
|
|
64
|
+
readonly violations: readonly PolicyViolation[];
|
|
65
|
+
}
|
|
66
|
+
/** Semantic outcome of a GATE policy evaluation. */
|
|
67
|
+
type GateOutcome = Outcome<GateStatus, GateOutcomeData>;
|
|
68
|
+
/**
|
|
69
|
+
* Contract every versioned gate engine must satisfy.
|
|
70
|
+
* Receives an already-parsed `GatePayload`; parsing from raw `unknown` is
|
|
71
|
+
* the registry's responsibility via `parseGatePayload`.
|
|
72
|
+
*/
|
|
73
|
+
interface VersionedGateEngine {
|
|
74
|
+
readonly version: number;
|
|
75
|
+
evaluate(payload: GatePayload, context: PolicyContext): Result<GateOutcome, string>;
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
3
78
|
//#region src/core/policies/engines/condition-evaluator-reporter.d.ts
|
|
4
79
|
interface ConditionEvaluationCause {
|
|
5
80
|
readonly name: string;
|
|
@@ -93,79 +168,5 @@ declare class CoreConfig {
|
|
|
93
168
|
getConditionEvaluationOptions(engineVersion: number): ConditionEvaluationOptions;
|
|
94
169
|
}
|
|
95
170
|
//#endregion
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
interface ConditionLeafNode {
|
|
99
|
-
readonly field: string;
|
|
100
|
-
readonly op: ConditionOp;
|
|
101
|
-
readonly value: unknown;
|
|
102
|
-
readonly allowNull?: true;
|
|
103
|
-
}
|
|
104
|
-
interface ConditionAndNode {
|
|
105
|
-
readonly and: readonly ConditionNode[];
|
|
106
|
-
}
|
|
107
|
-
interface ConditionOrNode {
|
|
108
|
-
readonly or: readonly ConditionNode[];
|
|
109
|
-
}
|
|
110
|
-
interface ConditionNotNode {
|
|
111
|
-
readonly not: ConditionNode;
|
|
112
|
-
}
|
|
113
|
-
type ConditionNode = ConditionLeafNode | ConditionAndNode | ConditionOrNode | ConditionNotNode;
|
|
114
|
-
//#endregion
|
|
115
|
-
//#region src/core/policies/engines/v1/gate/gate-types-v1.d.ts
|
|
116
|
-
type GatePayloadV1 = {
|
|
117
|
-
readonly condition: ConditionNode;
|
|
118
|
-
} | {
|
|
119
|
-
readonly allowIf: ConditionNode;
|
|
120
|
-
readonly defaultOutcome: "ALLOW" | "DENY";
|
|
121
|
-
};
|
|
122
|
-
//#endregion
|
|
123
|
-
//#region src/core/policies/engines/gate-payload.d.ts
|
|
124
|
-
type GatePayload = GatePayloadV1;
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/core/policies/engines/gate-types.d.ts
|
|
127
|
-
type PolicyContext = Record<string, unknown>;
|
|
128
|
-
interface GateTraceLeafSnapshot {
|
|
129
|
-
readonly kind: "LEAF";
|
|
130
|
-
readonly field: string;
|
|
131
|
-
readonly op: string;
|
|
132
|
-
readonly allowNull?: true;
|
|
133
|
-
}
|
|
134
|
-
type GateTraceNodeSnapshot = GateTraceLeafSnapshot | {
|
|
135
|
-
readonly kind: "AND" | "OR";
|
|
136
|
-
readonly childCount: number;
|
|
137
|
-
} | {
|
|
138
|
-
readonly kind: "NOT";
|
|
139
|
-
};
|
|
140
|
-
interface GateViolationTrace {
|
|
141
|
-
readonly conditionPath: string;
|
|
142
|
-
readonly decisiveNode: GateTraceNodeSnapshot;
|
|
143
|
-
readonly lastEvaluatedLeaf: GateTraceLeafSnapshot;
|
|
144
|
-
readonly lastEvaluatedLeafPath: string;
|
|
145
|
-
readonly lastEvaluatedLeafResult: boolean;
|
|
146
|
-
readonly field: string;
|
|
147
|
-
readonly op: string;
|
|
148
|
-
}
|
|
149
|
-
interface PolicyViolation {
|
|
150
|
-
readonly code: string;
|
|
151
|
-
readonly message: string;
|
|
152
|
-
readonly trace?: GateViolationTrace;
|
|
153
|
-
}
|
|
154
|
-
type GateStatus = "ALLOW" | "DENY";
|
|
155
|
-
interface GateOutcomeData {
|
|
156
|
-
readonly violations: readonly PolicyViolation[];
|
|
157
|
-
}
|
|
158
|
-
/** Semantic outcome of a GATE policy evaluation. */
|
|
159
|
-
type GateOutcome = Outcome<GateStatus, GateOutcomeData>;
|
|
160
|
-
/**
|
|
161
|
-
* Contract every versioned gate engine must satisfy.
|
|
162
|
-
* Receives an already-parsed `GatePayload`; parsing from raw `unknown` is
|
|
163
|
-
* the registry's responsibility via `parseGatePayload`.
|
|
164
|
-
*/
|
|
165
|
-
interface VersionedGateEngine {
|
|
166
|
-
readonly version: number;
|
|
167
|
-
evaluate(payload: GatePayload, context: PolicyContext): Result<GateOutcome, string>;
|
|
168
|
-
}
|
|
169
|
-
//#endregion
|
|
170
|
-
export { ConditionEvaluationReportTag as A, asPolicyDefinitionId as C, ConditionEvaluationOptions as D, ConditionEvaluationCause as E, ConditionEvaluationReport as O, asPolicyDecisionId as S, asTenantId as T, PolicyReporter as _, GateTraceNodeSnapshot as a, SchoolId as b, PolicyViolation as c, GatePayloadV1 as d, ConditionLeafNode as f, CoreObservabilityConfig as g, CoreConfigOptions as h, GateTraceLeafSnapshot as i, ConditionEvaluatorReporter as j, ConditionEvaluationReportLevel as k, VersionedGateEngine as l, CoreConfig as m, GateOutcomeData as n, GateViolationTrace as o, ConditionNode as p, GateStatus as r, PolicyContext as s, GateOutcome as t, GatePayload as u, PolicyDecisionId as v, asSchoolId as w, TenantId as x, PolicyDefinitionId as y };
|
|
171
|
-
//# sourceMappingURL=gate-types.d.ts.map
|
|
171
|
+
export { ConditionLeafNode as A, GateTraceNodeSnapshot as C, VersionedGateEngine as D, PolicyViolation as E, GatePayload as O, GateTraceLeafSnapshot as S, PolicyContext as T, ConditionEvaluationReportTag as _, PolicyDecisionId as a, GateOutcomeData as b, TenantId as c, asSchoolId as d, asTenantId as f, ConditionEvaluationReportLevel as g, ConditionEvaluationReport as h, PolicyReporter as i, ConditionNode as j, GatePayloadV1 as k, asPolicyDecisionId as l, ConditionEvaluationOptions as m, CoreConfigOptions as n, PolicyDefinitionId as o, ConditionEvaluationCause as p, CoreObservabilityConfig as r, SchoolId as s, CoreConfig as t, asPolicyDefinitionId as u, ConditionEvaluatorReporter as v, GateViolationTrace as w, GateStatus as x, GateOutcome as y };
|
|
172
|
+
//# sourceMappingURL=core-config.d.cts.map
|
|
@@ -1,5 +1,80 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as Result } from "./result.js";
|
|
2
|
+
import { n as Outcome } from "./outcome.js";
|
|
2
3
|
|
|
4
|
+
//#region src/core/policies/engines/v1/condition-types.d.ts
|
|
5
|
+
type ConditionOp = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "isNull" | "isNotNull";
|
|
6
|
+
interface ConditionLeafNode {
|
|
7
|
+
readonly field: string;
|
|
8
|
+
readonly op: ConditionOp;
|
|
9
|
+
readonly value: unknown;
|
|
10
|
+
readonly allowNull?: true;
|
|
11
|
+
}
|
|
12
|
+
interface ConditionAndNode {
|
|
13
|
+
readonly and: readonly ConditionNode[];
|
|
14
|
+
}
|
|
15
|
+
interface ConditionOrNode {
|
|
16
|
+
readonly or: readonly ConditionNode[];
|
|
17
|
+
}
|
|
18
|
+
interface ConditionNotNode {
|
|
19
|
+
readonly not: ConditionNode;
|
|
20
|
+
}
|
|
21
|
+
type ConditionNode = ConditionLeafNode | ConditionAndNode | ConditionOrNode | ConditionNotNode;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/core/policies/engines/v1/gate/gate-types-v1.d.ts
|
|
24
|
+
type GatePayloadV1 = {
|
|
25
|
+
readonly condition: ConditionNode;
|
|
26
|
+
} | {
|
|
27
|
+
readonly allowIf: ConditionNode;
|
|
28
|
+
readonly defaultOutcome: "ALLOW" | "DENY";
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/core/policies/engines/gate-payload.d.ts
|
|
32
|
+
type GatePayload = GatePayloadV1;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/core/policies/engines/gate-types.d.ts
|
|
35
|
+
type PolicyContext = Record<string, unknown>;
|
|
36
|
+
interface GateTraceLeafSnapshot {
|
|
37
|
+
readonly kind: "LEAF";
|
|
38
|
+
readonly field: string;
|
|
39
|
+
readonly op: string;
|
|
40
|
+
readonly allowNull?: true;
|
|
41
|
+
}
|
|
42
|
+
type GateTraceNodeSnapshot = GateTraceLeafSnapshot | {
|
|
43
|
+
readonly kind: "AND" | "OR";
|
|
44
|
+
readonly childCount: number;
|
|
45
|
+
} | {
|
|
46
|
+
readonly kind: "NOT";
|
|
47
|
+
};
|
|
48
|
+
interface GateViolationTrace {
|
|
49
|
+
readonly conditionPath: string;
|
|
50
|
+
readonly decisiveNode: GateTraceNodeSnapshot;
|
|
51
|
+
readonly lastEvaluatedLeaf: GateTraceLeafSnapshot;
|
|
52
|
+
readonly lastEvaluatedLeafPath: string;
|
|
53
|
+
readonly lastEvaluatedLeafResult: boolean;
|
|
54
|
+
readonly field: string;
|
|
55
|
+
readonly op: string;
|
|
56
|
+
}
|
|
57
|
+
interface PolicyViolation {
|
|
58
|
+
readonly code: string;
|
|
59
|
+
readonly message: string;
|
|
60
|
+
readonly trace?: GateViolationTrace;
|
|
61
|
+
}
|
|
62
|
+
type GateStatus = "ALLOW" | "DENY";
|
|
63
|
+
interface GateOutcomeData {
|
|
64
|
+
readonly violations: readonly PolicyViolation[];
|
|
65
|
+
}
|
|
66
|
+
/** Semantic outcome of a GATE policy evaluation. */
|
|
67
|
+
type GateOutcome = Outcome<GateStatus, GateOutcomeData>;
|
|
68
|
+
/**
|
|
69
|
+
* Contract every versioned gate engine must satisfy.
|
|
70
|
+
* Receives an already-parsed `GatePayload`; parsing from raw `unknown` is
|
|
71
|
+
* the registry's responsibility via `parseGatePayload`.
|
|
72
|
+
*/
|
|
73
|
+
interface VersionedGateEngine {
|
|
74
|
+
readonly version: number;
|
|
75
|
+
evaluate(payload: GatePayload, context: PolicyContext): Result<GateOutcome, string>;
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
3
78
|
//#region src/core/policies/engines/condition-evaluator-reporter.d.ts
|
|
4
79
|
interface ConditionEvaluationCause {
|
|
5
80
|
readonly name: string;
|
|
@@ -93,79 +168,5 @@ declare class CoreConfig {
|
|
|
93
168
|
getConditionEvaluationOptions(engineVersion: number): ConditionEvaluationOptions;
|
|
94
169
|
}
|
|
95
170
|
//#endregion
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
interface ConditionLeafNode {
|
|
99
|
-
readonly field: string;
|
|
100
|
-
readonly op: ConditionOp;
|
|
101
|
-
readonly value: unknown;
|
|
102
|
-
readonly allowNull?: true;
|
|
103
|
-
}
|
|
104
|
-
interface ConditionAndNode {
|
|
105
|
-
readonly and: readonly ConditionNode[];
|
|
106
|
-
}
|
|
107
|
-
interface ConditionOrNode {
|
|
108
|
-
readonly or: readonly ConditionNode[];
|
|
109
|
-
}
|
|
110
|
-
interface ConditionNotNode {
|
|
111
|
-
readonly not: ConditionNode;
|
|
112
|
-
}
|
|
113
|
-
type ConditionNode = ConditionLeafNode | ConditionAndNode | ConditionOrNode | ConditionNotNode;
|
|
114
|
-
//#endregion
|
|
115
|
-
//#region src/core/policies/engines/v1/gate/gate-types-v1.d.ts
|
|
116
|
-
type GatePayloadV1 = {
|
|
117
|
-
readonly condition: ConditionNode;
|
|
118
|
-
} | {
|
|
119
|
-
readonly allowIf: ConditionNode;
|
|
120
|
-
readonly defaultOutcome: "ALLOW" | "DENY";
|
|
121
|
-
};
|
|
122
|
-
//#endregion
|
|
123
|
-
//#region src/core/policies/engines/gate-payload.d.ts
|
|
124
|
-
type GatePayload = GatePayloadV1;
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/core/policies/engines/gate-types.d.ts
|
|
127
|
-
type PolicyContext = Record<string, unknown>;
|
|
128
|
-
interface GateTraceLeafSnapshot {
|
|
129
|
-
readonly kind: "LEAF";
|
|
130
|
-
readonly field: string;
|
|
131
|
-
readonly op: string;
|
|
132
|
-
readonly allowNull?: true;
|
|
133
|
-
}
|
|
134
|
-
type GateTraceNodeSnapshot = GateTraceLeafSnapshot | {
|
|
135
|
-
readonly kind: "AND" | "OR";
|
|
136
|
-
readonly childCount: number;
|
|
137
|
-
} | {
|
|
138
|
-
readonly kind: "NOT";
|
|
139
|
-
};
|
|
140
|
-
interface GateViolationTrace {
|
|
141
|
-
readonly conditionPath: string;
|
|
142
|
-
readonly decisiveNode: GateTraceNodeSnapshot;
|
|
143
|
-
readonly lastEvaluatedLeaf: GateTraceLeafSnapshot;
|
|
144
|
-
readonly lastEvaluatedLeafPath: string;
|
|
145
|
-
readonly lastEvaluatedLeafResult: boolean;
|
|
146
|
-
readonly field: string;
|
|
147
|
-
readonly op: string;
|
|
148
|
-
}
|
|
149
|
-
interface PolicyViolation {
|
|
150
|
-
readonly code: string;
|
|
151
|
-
readonly message: string;
|
|
152
|
-
readonly trace?: GateViolationTrace;
|
|
153
|
-
}
|
|
154
|
-
type GateStatus = "ALLOW" | "DENY";
|
|
155
|
-
interface GateOutcomeData {
|
|
156
|
-
readonly violations: readonly PolicyViolation[];
|
|
157
|
-
}
|
|
158
|
-
/** Semantic outcome of a GATE policy evaluation. */
|
|
159
|
-
type GateOutcome = Outcome<GateStatus, GateOutcomeData>;
|
|
160
|
-
/**
|
|
161
|
-
* Contract every versioned gate engine must satisfy.
|
|
162
|
-
* Receives an already-parsed `GatePayload`; parsing from raw `unknown` is
|
|
163
|
-
* the registry's responsibility via `parseGatePayload`.
|
|
164
|
-
*/
|
|
165
|
-
interface VersionedGateEngine {
|
|
166
|
-
readonly version: number;
|
|
167
|
-
evaluate(payload: GatePayload, context: PolicyContext): Result<GateOutcome, string>;
|
|
168
|
-
}
|
|
169
|
-
//#endregion
|
|
170
|
-
export { ConditionEvaluationReportTag as A, asPolicyDefinitionId as C, ConditionEvaluationOptions as D, ConditionEvaluationCause as E, ConditionEvaluationReport as O, asPolicyDecisionId as S, asTenantId as T, PolicyReporter as _, GateTraceNodeSnapshot as a, SchoolId as b, PolicyViolation as c, GatePayloadV1 as d, ConditionLeafNode as f, CoreObservabilityConfig as g, CoreConfigOptions as h, GateTraceLeafSnapshot as i, ConditionEvaluatorReporter as j, ConditionEvaluationReportLevel as k, VersionedGateEngine as l, CoreConfig as m, GateOutcomeData as n, GateViolationTrace as o, ConditionNode as p, GateStatus as r, PolicyContext as s, GateOutcome as t, GatePayload as u, PolicyDecisionId as v, asSchoolId as w, TenantId as x, PolicyDefinitionId as y };
|
|
171
|
-
//# sourceMappingURL=gate-types.d.cts.map
|
|
171
|
+
export { ConditionLeafNode as A, GateTraceNodeSnapshot as C, VersionedGateEngine as D, PolicyViolation as E, GatePayload as O, GateTraceLeafSnapshot as S, PolicyContext as T, ConditionEvaluationReportTag as _, PolicyDecisionId as a, GateOutcomeData as b, TenantId as c, asSchoolId as d, asTenantId as f, ConditionEvaluationReportLevel as g, ConditionEvaluationReport as h, PolicyReporter as i, ConditionNode as j, GatePayloadV1 as k, asPolicyDecisionId as l, ConditionEvaluationOptions as m, CoreConfigOptions as n, PolicyDefinitionId as o, ConditionEvaluationCause as p, CoreObservabilityConfig as r, SchoolId as s, CoreConfig as t, asPolicyDefinitionId as u, ConditionEvaluatorReporter as v, GateViolationTrace as w, GateStatus as x, GateOutcome as y };
|
|
172
|
+
//# sourceMappingURL=core-config.d.ts.map
|
package/dist/domain/index.cjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_entity = require("../entity.cjs");
|
|
2
3
|
const require_value_object = require("../value-object.cjs");
|
|
3
4
|
const require_uuid_identifier = require("../uuid-identifier.cjs");
|
|
4
5
|
Object.defineProperty(exports, "Entity", {
|
|
5
6
|
enumerable: true,
|
|
6
7
|
get: function() {
|
|
7
|
-
return
|
|
8
|
+
return require_entity.Entity;
|
|
8
9
|
}
|
|
9
10
|
});
|
|
10
11
|
exports.UuidIdentifier = require_uuid_identifier.UuidIdentifier;
|
package/dist/domain/index.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { t as DeepReadonly } from "../immutable.cjs";
|
|
2
|
-
import {
|
|
2
|
+
import { n as ValueObjectPluginContract, t as ValueObject } from "../value-object.cjs";
|
|
3
|
+
import { n as Entity, r as EntityState, t as UuidIdentifier } from "../uuid-identifier.cjs";
|
|
3
4
|
export { type DeepReadonly, Entity, type EntityState, UuidIdentifier, ValueObject, type ValueObjectPluginContract };
|
package/dist/domain/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { t as DeepReadonly } from "../immutable.js";
|
|
2
|
-
import {
|
|
2
|
+
import { n as ValueObjectPluginContract, t as ValueObject } from "../value-object.js";
|
|
3
|
+
import { n as Entity, r as EntityState, t as UuidIdentifier } from "../uuid-identifier.js";
|
|
3
4
|
export { type DeepReadonly, Entity, type EntityState, UuidIdentifier, ValueObject, type ValueObjectPluginContract };
|
package/dist/domain/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as Entity } from "../entity.js";
|
|
2
|
+
import { t as ValueObject } from "../value-object.js";
|
|
2
3
|
import { t as UuidIdentifier } from "../uuid-identifier.js";
|
|
3
4
|
export { Entity, UuidIdentifier, ValueObject };
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
const require_use_case = require("./use-case.cjs");
|
|
2
|
+
const require_entity = require("./entity.cjs");
|
|
2
3
|
const require_value_object = require("./value-object.cjs");
|
|
3
4
|
//#region src/core/versioning/domain-event-contracts.ts
|
|
4
5
|
function buildDomainEventContractVersions(selection) {
|
|
5
6
|
const contractVersions = {};
|
|
6
|
-
if (selection.entity) contractVersions.entity_contract =
|
|
7
|
+
if (selection.entity) contractVersions.entity_contract = require_entity.Entity.CONTRACT_VERSION;
|
|
7
8
|
if (selection.valueObject) contractVersions.value_object_contract = require_value_object.ValueObject.CONTRACT_VERSION;
|
|
8
9
|
if (selection.useCase) contractVersions.use_case_contract = require_use_case.UseCase.CONTRACT_VERSION;
|
|
9
10
|
return Object.freeze(contractVersions);
|
|
10
11
|
}
|
|
11
12
|
function createDomainEventEnvelope(input) {
|
|
12
|
-
|
|
13
|
+
require_entity.assertValidAggregateVersion(input.aggregateVersion);
|
|
13
14
|
return Object.freeze({
|
|
14
15
|
aggregate_version: input.aggregateVersion,
|
|
15
16
|
payload: input.payload,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain-event-contracts.cjs","names":["Entity","ValueObject","UseCase"],"sources":["../src/core/versioning/domain-event-contracts.ts"],"sourcesContent":["import { UseCase } from \"../application/use-case.js\";\nimport { Entity } from \"../domain/entity.js\";\nimport { ValueObject } from \"../domain/value-object.js\";\nimport { assertValidAggregateVersion } from \"../shared/aggregate-version.js\";\nimport { type ContractVersion } from \"./version.js\";\n\ninterface DomainEventContractSelection {\n readonly entity?: boolean;\n readonly valueObject?: boolean;\n readonly useCase?: boolean;\n}\n\ninterface DomainEventContractVersions {\n readonly entity_contract?: ContractVersion;\n readonly value_object_contract?: ContractVersion;\n readonly use_case_contract?: ContractVersion;\n}\n\ninterface CreateDomainEventEnvelopeInput<TPayload> {\n readonly aggregateVersion: number;\n readonly payload: TPayload;\n readonly contracts: DomainEventContractSelection;\n}\n\ninterface DomainEventEnvelope<TPayload> extends DomainEventContractVersions {\n readonly aggregate_version: number;\n readonly payload: TPayload;\n}\n\nfunction buildDomainEventContractVersions(\n selection: DomainEventContractSelection,\n): DomainEventContractVersions {\n const contractVersions: {\n entity_contract?: ContractVersion;\n value_object_contract?: ContractVersion;\n use_case_contract?: ContractVersion;\n } = {};\n\n if (selection.entity) {\n contractVersions.entity_contract = Entity.CONTRACT_VERSION;\n }\n\n if (selection.valueObject) {\n contractVersions.value_object_contract = ValueObject.CONTRACT_VERSION;\n }\n\n if (selection.useCase) {\n contractVersions.use_case_contract = UseCase.CONTRACT_VERSION;\n }\n\n return Object.freeze(contractVersions);\n}\n\nfunction createDomainEventEnvelope<TPayload>(\n input: CreateDomainEventEnvelopeInput<TPayload>,\n): DomainEventEnvelope<TPayload> {\n assertValidAggregateVersion(input.aggregateVersion);\n\n return Object.freeze({\n aggregate_version: input.aggregateVersion,\n payload: input.payload,\n ...buildDomainEventContractVersions(input.contracts),\n });\n}\n\nexport {\n buildDomainEventContractVersions,\n createDomainEventEnvelope,\n type CreateDomainEventEnvelopeInput,\n type DomainEventContractSelection,\n type DomainEventContractVersions,\n type DomainEventEnvelope,\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"domain-event-contracts.cjs","names":["Entity","ValueObject","UseCase"],"sources":["../src/core/versioning/domain-event-contracts.ts"],"sourcesContent":["import { UseCase } from \"../application/use-case.js\";\nimport { Entity } from \"../domain/entity.js\";\nimport { ValueObject } from \"../domain/value-object.js\";\nimport { assertValidAggregateVersion } from \"../shared/aggregate-version.js\";\nimport { type ContractVersion } from \"./version.js\";\n\ninterface DomainEventContractSelection {\n readonly entity?: boolean;\n readonly valueObject?: boolean;\n readonly useCase?: boolean;\n}\n\ninterface DomainEventContractVersions {\n readonly entity_contract?: ContractVersion;\n readonly value_object_contract?: ContractVersion;\n readonly use_case_contract?: ContractVersion;\n}\n\ninterface CreateDomainEventEnvelopeInput<TPayload> {\n readonly aggregateVersion: number;\n readonly payload: TPayload;\n readonly contracts: DomainEventContractSelection;\n}\n\ninterface DomainEventEnvelope<TPayload> extends DomainEventContractVersions {\n readonly aggregate_version: number;\n readonly payload: TPayload;\n}\n\nfunction buildDomainEventContractVersions(\n selection: DomainEventContractSelection,\n): DomainEventContractVersions {\n const contractVersions: {\n entity_contract?: ContractVersion;\n value_object_contract?: ContractVersion;\n use_case_contract?: ContractVersion;\n } = {};\n\n if (selection.entity) {\n contractVersions.entity_contract = Entity.CONTRACT_VERSION;\n }\n\n if (selection.valueObject) {\n contractVersions.value_object_contract = ValueObject.CONTRACT_VERSION;\n }\n\n if (selection.useCase) {\n contractVersions.use_case_contract = UseCase.CONTRACT_VERSION;\n }\n\n return Object.freeze(contractVersions);\n}\n\nfunction createDomainEventEnvelope<TPayload>(\n input: CreateDomainEventEnvelopeInput<TPayload>,\n): DomainEventEnvelope<TPayload> {\n assertValidAggregateVersion(input.aggregateVersion);\n\n return Object.freeze({\n aggregate_version: input.aggregateVersion,\n payload: input.payload,\n ...buildDomainEventContractVersions(input.contracts),\n });\n}\n\nexport {\n buildDomainEventContractVersions,\n createDomainEventEnvelope,\n type CreateDomainEventEnvelopeInput,\n type DomainEventContractSelection,\n type DomainEventContractVersions,\n type DomainEventEnvelope,\n};\n"],"mappings":";;;;AA6BA,SAAS,iCACL,WAC2B;CAC3B,MAAM,mBAIF,CAAC;CAEL,IAAI,UAAU,QACV,iBAAiB,kBAAkBA,eAAAA,OAAO;CAG9C,IAAI,UAAU,aACV,iBAAiB,wBAAwBC,qBAAAA,YAAY;CAGzD,IAAI,UAAU,SACV,iBAAiB,oBAAoBC,iBAAAA,QAAQ;CAGjD,OAAO,OAAO,OAAO,gBAAgB;AACzC;AAEA,SAAS,0BACL,OAC6B;CAC7B,eAAA,4BAA4B,MAAM,gBAAgB;CAElD,OAAO,OAAO,OAAO;EACjB,mBAAmB,MAAM;EACzB,SAAS,MAAM;EACf,GAAG,iCAAiC,MAAM,SAAS;CACvD,CAAC;AACL"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { t as UseCase } from "./use-case.js";
|
|
2
|
-
import { n as
|
|
2
|
+
import { n as assertValidAggregateVersion, t as Entity } from "./entity.js";
|
|
3
|
+
import { t as ValueObject } from "./value-object.js";
|
|
3
4
|
//#region src/core/versioning/domain-event-contracts.ts
|
|
4
5
|
function buildDomainEventContractVersions(selection) {
|
|
5
6
|
const contractVersions = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"domain-event-contracts.js","names":[],"sources":["../src/core/versioning/domain-event-contracts.ts"],"sourcesContent":["import { UseCase } from \"../application/use-case.js\";\nimport { Entity } from \"../domain/entity.js\";\nimport { ValueObject } from \"../domain/value-object.js\";\nimport { assertValidAggregateVersion } from \"../shared/aggregate-version.js\";\nimport { type ContractVersion } from \"./version.js\";\n\ninterface DomainEventContractSelection {\n readonly entity?: boolean;\n readonly valueObject?: boolean;\n readonly useCase?: boolean;\n}\n\ninterface DomainEventContractVersions {\n readonly entity_contract?: ContractVersion;\n readonly value_object_contract?: ContractVersion;\n readonly use_case_contract?: ContractVersion;\n}\n\ninterface CreateDomainEventEnvelopeInput<TPayload> {\n readonly aggregateVersion: number;\n readonly payload: TPayload;\n readonly contracts: DomainEventContractSelection;\n}\n\ninterface DomainEventEnvelope<TPayload> extends DomainEventContractVersions {\n readonly aggregate_version: number;\n readonly payload: TPayload;\n}\n\nfunction buildDomainEventContractVersions(\n selection: DomainEventContractSelection,\n): DomainEventContractVersions {\n const contractVersions: {\n entity_contract?: ContractVersion;\n value_object_contract?: ContractVersion;\n use_case_contract?: ContractVersion;\n } = {};\n\n if (selection.entity) {\n contractVersions.entity_contract = Entity.CONTRACT_VERSION;\n }\n\n if (selection.valueObject) {\n contractVersions.value_object_contract = ValueObject.CONTRACT_VERSION;\n }\n\n if (selection.useCase) {\n contractVersions.use_case_contract = UseCase.CONTRACT_VERSION;\n }\n\n return Object.freeze(contractVersions);\n}\n\nfunction createDomainEventEnvelope<TPayload>(\n input: CreateDomainEventEnvelopeInput<TPayload>,\n): DomainEventEnvelope<TPayload> {\n assertValidAggregateVersion(input.aggregateVersion);\n\n return Object.freeze({\n aggregate_version: input.aggregateVersion,\n payload: input.payload,\n ...buildDomainEventContractVersions(input.contracts),\n });\n}\n\nexport {\n buildDomainEventContractVersions,\n createDomainEventEnvelope,\n type CreateDomainEventEnvelopeInput,\n type DomainEventContractSelection,\n type DomainEventContractVersions,\n type DomainEventEnvelope,\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"domain-event-contracts.js","names":[],"sources":["../src/core/versioning/domain-event-contracts.ts"],"sourcesContent":["import { UseCase } from \"../application/use-case.js\";\nimport { Entity } from \"../domain/entity.js\";\nimport { ValueObject } from \"../domain/value-object.js\";\nimport { assertValidAggregateVersion } from \"../shared/aggregate-version.js\";\nimport { type ContractVersion } from \"./version.js\";\n\ninterface DomainEventContractSelection {\n readonly entity?: boolean;\n readonly valueObject?: boolean;\n readonly useCase?: boolean;\n}\n\ninterface DomainEventContractVersions {\n readonly entity_contract?: ContractVersion;\n readonly value_object_contract?: ContractVersion;\n readonly use_case_contract?: ContractVersion;\n}\n\ninterface CreateDomainEventEnvelopeInput<TPayload> {\n readonly aggregateVersion: number;\n readonly payload: TPayload;\n readonly contracts: DomainEventContractSelection;\n}\n\ninterface DomainEventEnvelope<TPayload> extends DomainEventContractVersions {\n readonly aggregate_version: number;\n readonly payload: TPayload;\n}\n\nfunction buildDomainEventContractVersions(\n selection: DomainEventContractSelection,\n): DomainEventContractVersions {\n const contractVersions: {\n entity_contract?: ContractVersion;\n value_object_contract?: ContractVersion;\n use_case_contract?: ContractVersion;\n } = {};\n\n if (selection.entity) {\n contractVersions.entity_contract = Entity.CONTRACT_VERSION;\n }\n\n if (selection.valueObject) {\n contractVersions.value_object_contract = ValueObject.CONTRACT_VERSION;\n }\n\n if (selection.useCase) {\n contractVersions.use_case_contract = UseCase.CONTRACT_VERSION;\n }\n\n return Object.freeze(contractVersions);\n}\n\nfunction createDomainEventEnvelope<TPayload>(\n input: CreateDomainEventEnvelopeInput<TPayload>,\n): DomainEventEnvelope<TPayload> {\n assertValidAggregateVersion(input.aggregateVersion);\n\n return Object.freeze({\n aggregate_version: input.aggregateVersion,\n payload: input.payload,\n ...buildDomainEventContractVersions(input.contracts),\n });\n}\n\nexport {\n buildDomainEventContractVersions,\n createDomainEventEnvelope,\n type CreateDomainEventEnvelopeInput,\n type DomainEventContractSelection,\n type DomainEventContractVersions,\n type DomainEventEnvelope,\n};\n"],"mappings":";;;;AA6BA,SAAS,iCACL,WAC2B;CAC3B,MAAM,mBAIF,CAAC;CAEL,IAAI,UAAU,QACV,iBAAiB,kBAAkB,OAAO;CAG9C,IAAI,UAAU,aACV,iBAAiB,wBAAwB,YAAY;CAGzD,IAAI,UAAU,SACV,iBAAiB,oBAAoB,QAAQ;CAGjD,OAAO,OAAO,OAAO,gBAAgB;AACzC;AAEA,SAAS,0BACL,OAC6B;CAC7B,4BAA4B,MAAM,gBAAgB;CAElD,OAAO,OAAO,OAAO;EACjB,mBAAmB,MAAM;EACzB,SAAS,MAAM;EACf,GAAG,iCAAiC,MAAM,SAAS;CACvD,CAAC;AACL"}
|
package/dist/entity.cjs
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const require_invariant_violation_exception = require("./invariant-violation-exception.cjs");
|
|
2
|
+
const require_immutable = require("./immutable.cjs");
|
|
3
|
+
const require_temporal_guards = require("./temporal-guards.cjs");
|
|
4
|
+
//#region src/core/shared/aggregate-version.ts
|
|
5
|
+
function assertValidAggregateVersion(aggregateVersion) {
|
|
6
|
+
if (!Number.isInteger(aggregateVersion) || aggregateVersion < 0) throw new require_invariant_violation_exception.InvariantViolationException(`aggregateVersion must be a non-negative integer. Received: ${aggregateVersion}`);
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/core/domain/entity.ts
|
|
10
|
+
var _Entity;
|
|
11
|
+
/**
|
|
12
|
+
* Base class for domain entities — objects defined by a stable identity rather
|
|
13
|
+
* than by their attributes. Two entities are "the same" when their `id`
|
|
14
|
+
* matches, even if every other field differs; this is the opposite of a
|
|
15
|
+
* {@link ValueObject}, which is defined entirely by its contents.
|
|
16
|
+
*
|
|
17
|
+
* The class owns the bookkeeping common to every aggregate root: a creation
|
|
18
|
+
* timestamp that never changes, a last-modified timestamp, and an
|
|
19
|
+
* `aggregateVersion` counter used for optimistic concurrency control. All three
|
|
20
|
+
* are validated on construction and the dates are defensively cloned, so an
|
|
21
|
+
* entity can never be built into — or leak — an inconsistent temporal state.
|
|
22
|
+
*
|
|
23
|
+
* @typeParam TIdentifier - The identity type (e.g. a branded string id or a VO).
|
|
24
|
+
*/
|
|
25
|
+
let Entity = class Entity {
|
|
26
|
+
static {
|
|
27
|
+
_Entity = this;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Reconstitutes an entity from its persisted {@link EntityState}.
|
|
31
|
+
*
|
|
32
|
+
* Validates the temporal invariants up front so an invalid entity is
|
|
33
|
+
* impossible to construct: both dates must be valid, the aggregate version
|
|
34
|
+
* must be a non-negative integer, and `updatedAt` may not predate
|
|
35
|
+
* `createdAt`. Both dates are cloned on the way in so a later mutation of
|
|
36
|
+
* the caller's `Date` objects cannot reach into the entity's internal state.
|
|
37
|
+
*
|
|
38
|
+
* Declared `protected` because entities are reconstituted through a
|
|
39
|
+
* subclass factory, never instantiated directly by application code.
|
|
40
|
+
*
|
|
41
|
+
* @throws {InvariantViolationException} When `updatedAt` is earlier than `createdAt`.
|
|
42
|
+
*/
|
|
43
|
+
constructor(state) {
|
|
44
|
+
require_temporal_guards.assertValidDate("createdAt", state.createdAt);
|
|
45
|
+
require_temporal_guards.assertValidDate("updatedAt", state.updatedAt);
|
|
46
|
+
assertValidAggregateVersion(state.aggregateVersion);
|
|
47
|
+
if (state.updatedAt.getTime() < state.createdAt.getTime()) throw new require_invariant_violation_exception.InvariantViolationException("updatedAt cannot be earlier than createdAt");
|
|
48
|
+
this._id = state.id;
|
|
49
|
+
this._createdAt = require_temporal_guards.cloneDate(state.createdAt);
|
|
50
|
+
this._updatedAt = require_temporal_guards.cloneDate(state.updatedAt);
|
|
51
|
+
this._aggregateVersion = state.aggregateVersion;
|
|
52
|
+
}
|
|
53
|
+
/** The entity's stable identity — the basis for equality between entities. */
|
|
54
|
+
get id() {
|
|
55
|
+
return this._id;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* When the entity was first created.
|
|
59
|
+
*
|
|
60
|
+
* Returns a clone so callers cannot mutate the entity's internal `Date`;
|
|
61
|
+
* the value is fixed at construction and never changes thereafter.
|
|
62
|
+
*/
|
|
63
|
+
get createdAt() {
|
|
64
|
+
return require_temporal_guards.cloneDate(this._createdAt);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* When the entity was last modified.
|
|
68
|
+
*
|
|
69
|
+
* Returns a clone for the same encapsulation reason as {@link createdAt};
|
|
70
|
+
* the underlying value advances only through {@link markAsModified}.
|
|
71
|
+
*/
|
|
72
|
+
get updatedAt() {
|
|
73
|
+
return require_temporal_guards.cloneDate(this._updatedAt);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Monotonic counter incremented on every mutation, used for optimistic
|
|
77
|
+
* concurrency control: a writer reads this value, and the persistence layer
|
|
78
|
+
* rejects the write if the stored version has moved on in the meantime.
|
|
79
|
+
*/
|
|
80
|
+
get aggregateVersion() {
|
|
81
|
+
return this._aggregateVersion;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The schema/contract version stamped on this entity type by the
|
|
85
|
+
* `@version` decorator — used to detect and migrate state persisted under
|
|
86
|
+
* an older shape.
|
|
87
|
+
*/
|
|
88
|
+
get contractVersion() {
|
|
89
|
+
return _Entity.CONTRACT_VERSION;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The single seam through which an entity records a mutation: it advances
|
|
93
|
+
* `updatedAt` and bumps {@link aggregateVersion} by one. Subclasses must
|
|
94
|
+
* call this from every state-changing method so the version counter stays
|
|
95
|
+
* an accurate optimistic-lock token.
|
|
96
|
+
*
|
|
97
|
+
* @param updatedAt - The modification instant; defaults to now. Validated
|
|
98
|
+
* and required not to predate `createdAt`, preserving the same invariant
|
|
99
|
+
* the constructor enforces.
|
|
100
|
+
* @returns The new aggregate version after the increment.
|
|
101
|
+
* @throws {InvariantViolationException} When `updatedAt` is earlier than `createdAt`.
|
|
102
|
+
*/
|
|
103
|
+
markAsModified(updatedAt = /* @__PURE__ */ new Date()) {
|
|
104
|
+
require_temporal_guards.assertValidDate("updatedAt", updatedAt);
|
|
105
|
+
if (updatedAt.getTime() < this._createdAt.getTime()) throw new require_invariant_violation_exception.InvariantViolationException("updatedAt cannot be earlier than createdAt");
|
|
106
|
+
this._updatedAt = require_temporal_guards.cloneDate(updatedAt);
|
|
107
|
+
this._aggregateVersion += 1;
|
|
108
|
+
return this._aggregateVersion;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
Entity = _Entity = require_immutable.__decorate([require_immutable.version("1.0")], Entity);
|
|
112
|
+
//#endregion
|
|
113
|
+
Object.defineProperty(exports, "Entity", {
|
|
114
|
+
enumerable: true,
|
|
115
|
+
get: function() {
|
|
116
|
+
return Entity;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
Object.defineProperty(exports, "assertValidAggregateVersion", {
|
|
120
|
+
enumerable: true,
|
|
121
|
+
get: function() {
|
|
122
|
+
return assertValidAggregateVersion;
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=entity.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity.cjs","names":["InvariantViolationException","InvariantViolationException","cloneDate","version"],"sources":["../src/core/shared/aggregate-version.ts","../src/core/domain/entity.ts"],"sourcesContent":["import { InvariantViolationException } from \"../exceptions/invariant-violation-exception.js\";\n\nfunction assertValidAggregateVersion(aggregateVersion: number): void {\n if (!Number.isInteger(aggregateVersion) || aggregateVersion < 0) {\n throw new InvariantViolationException(\n `aggregateVersion must be a non-negative integer. Received: ${aggregateVersion}`,\n );\n }\n}\n\nexport { assertValidAggregateVersion };\n","import { InvariantViolationException } from \"../exceptions/invariant-violation-exception.js\";\nimport { assertValidAggregateVersion } from \"../shared/aggregate-version.js\";\nimport { assertValidDate, cloneDate } from \"../shared/temporal-guards.js\";\nimport { type ContractVersion, version } from \"../versioning/version.js\";\n\n/**\n * The minimal persisted shape needed to reconstitute an {@link Entity}.\n *\n * This is the contract between storage and the domain: a repository maps a row\n * (or document) onto these four fields and hands them to a subclass constructor.\n * `aggregateVersion` travels with the state so optimistic-concurrency checks\n * survive a round-trip through the database.\n */\ninterface EntityState<TIdentifier> {\n readonly id: TIdentifier;\n readonly createdAt: Date;\n readonly updatedAt: Date;\n readonly aggregateVersion: number;\n}\n\n/**\n * Base class for domain entities — objects defined by a stable identity rather\n * than by their attributes. Two entities are \"the same\" when their `id`\n * matches, even if every other field differs; this is the opposite of a\n * {@link ValueObject}, which is defined entirely by its contents.\n *\n * The class owns the bookkeeping common to every aggregate root: a creation\n * timestamp that never changes, a last-modified timestamp, and an\n * `aggregateVersion` counter used for optimistic concurrency control. All three\n * are validated on construction and the dates are defensively cloned, so an\n * entity can never be built into — or leak — an inconsistent temporal state.\n *\n * @typeParam TIdentifier - The identity type (e.g. a branded string id or a VO).\n */\n@version(\"1.0\")\nabstract class Entity<TIdentifier> {\n declare public static readonly CONTRACT_VERSION: ContractVersion;\n\n private readonly _id: TIdentifier;\n private readonly _createdAt: Date;\n private _updatedAt: Date;\n private _aggregateVersion: number;\n\n /**\n * Reconstitutes an entity from its persisted {@link EntityState}.\n *\n * Validates the temporal invariants up front so an invalid entity is\n * impossible to construct: both dates must be valid, the aggregate version\n * must be a non-negative integer, and `updatedAt` may not predate\n * `createdAt`. Both dates are cloned on the way in so a later mutation of\n * the caller's `Date` objects cannot reach into the entity's internal state.\n *\n * Declared `protected` because entities are reconstituted through a\n * subclass factory, never instantiated directly by application code.\n *\n * @throws {InvariantViolationException} When `updatedAt` is earlier than `createdAt`.\n */\n protected constructor(state: EntityState<TIdentifier>) {\n assertValidDate(\"createdAt\", state.createdAt);\n assertValidDate(\"updatedAt\", state.updatedAt);\n assertValidAggregateVersion(state.aggregateVersion);\n\n if (state.updatedAt.getTime() < state.createdAt.getTime()) {\n throw new InvariantViolationException(\n \"updatedAt cannot be earlier than createdAt\",\n );\n }\n\n this._id = state.id;\n this._createdAt = cloneDate(state.createdAt);\n this._updatedAt = cloneDate(state.updatedAt);\n this._aggregateVersion = state.aggregateVersion;\n }\n\n /** The entity's stable identity — the basis for equality between entities. */\n public get id(): TIdentifier {\n return this._id;\n }\n\n /**\n * When the entity was first created.\n *\n * Returns a clone so callers cannot mutate the entity's internal `Date`;\n * the value is fixed at construction and never changes thereafter.\n */\n public get createdAt(): Date {\n return cloneDate(this._createdAt);\n }\n\n /**\n * When the entity was last modified.\n *\n * Returns a clone for the same encapsulation reason as {@link createdAt};\n * the underlying value advances only through {@link markAsModified}.\n */\n public get updatedAt(): Date {\n return cloneDate(this._updatedAt);\n }\n\n /**\n * Monotonic counter incremented on every mutation, used for optimistic\n * concurrency control: a writer reads this value, and the persistence layer\n * rejects the write if the stored version has moved on in the meantime.\n */\n public get aggregateVersion(): number {\n return this._aggregateVersion;\n }\n\n /**\n * The schema/contract version stamped on this entity type by the\n * `@version` decorator — used to detect and migrate state persisted under\n * an older shape.\n */\n public get contractVersion(): ContractVersion {\n return Entity.CONTRACT_VERSION;\n }\n\n /**\n * The single seam through which an entity records a mutation: it advances\n * `updatedAt` and bumps {@link aggregateVersion} by one. Subclasses must\n * call this from every state-changing method so the version counter stays\n * an accurate optimistic-lock token.\n *\n * @param updatedAt - The modification instant; defaults to now. Validated\n * and required not to predate `createdAt`, preserving the same invariant\n * the constructor enforces.\n * @returns The new aggregate version after the increment.\n * @throws {InvariantViolationException} When `updatedAt` is earlier than `createdAt`.\n */\n protected markAsModified(updatedAt: Date = new Date()): number {\n assertValidDate(\"updatedAt\", updatedAt);\n\n if (updatedAt.getTime() < this._createdAt.getTime()) {\n throw new InvariantViolationException(\n \"updatedAt cannot be earlier than createdAt\",\n );\n }\n\n this._updatedAt = cloneDate(updatedAt);\n this._aggregateVersion += 1;\n\n return this._aggregateVersion;\n }\n}\n\nexport { Entity, type EntityState };\n"],"mappings":";;;;AAEA,SAAS,4BAA4B,kBAAgC;CACjE,IAAI,CAAC,OAAO,UAAU,gBAAgB,KAAK,mBAAmB,GAC1D,MAAM,IAAIA,sCAAAA,4BACN,8DAA8D,kBAClE;AAER;;;;;;;;;;;;;;;;;;AC0BA,IAAA,SAAA,MACe,OAAoB;;;;;;;;;;;;;;;;;;CAsB/B,YAAsB,OAAiC;EACnD,wBAAA,gBAAgB,aAAa,MAAM,SAAS;EAC5C,wBAAA,gBAAgB,aAAa,MAAM,SAAS;EAC5C,4BAA4B,MAAM,gBAAgB;EAElD,IAAI,MAAM,UAAU,QAAQ,IAAI,MAAM,UAAU,QAAQ,GACpD,MAAM,IAAIC,sCAAAA,4BACN,4CACJ;EAGJ,KAAK,MAAM,MAAM;EACjB,KAAK,aAAaC,wBAAAA,UAAU,MAAM,SAAS;EAC3C,KAAK,aAAaA,wBAAAA,UAAU,MAAM,SAAS;EAC3C,KAAK,oBAAoB,MAAM;CACnC;;CAGA,IAAW,KAAkB;EACzB,OAAO,KAAK;CAChB;;;;;;;CAQA,IAAW,YAAkB;EACzB,OAAOA,wBAAAA,UAAU,KAAK,UAAU;CACpC;;;;;;;CAQA,IAAW,YAAkB;EACzB,OAAOA,wBAAAA,UAAU,KAAK,UAAU;CACpC;;;;;;CAOA,IAAW,mBAA2B;EAClC,OAAO,KAAK;CAChB;;;;;;CAOA,IAAW,kBAAmC;EAC1C,OAAA,QAAc;CAClB;;;;;;;;;;;;;CAcA,eAAyB,4BAAkB,IAAI,KAAK,GAAW;EAC3D,wBAAA,gBAAgB,aAAa,SAAS;EAEtC,IAAI,UAAU,QAAQ,IAAI,KAAK,WAAW,QAAQ,GAC9C,MAAM,IAAID,sCAAAA,4BACN,4CACJ;EAGJ,KAAK,aAAaC,wBAAAA,UAAU,SAAS;EACrC,KAAK,qBAAqB;EAE1B,OAAO,KAAK;CAChB;AACJ;iDA7GCC,kBAAAA,QAAQ,KAAK,CAAA,GAAA,MAAA"}
|