@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
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
export type { ComputePayload, ComputePayloadV1 } from "./compute-payload";
|
|
2
2
|
export type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
ComputeEvaluator,
|
|
4
|
+
ComputeEvaluatorRegistration,
|
|
5
|
+
ComputeOutcome,
|
|
6
|
+
ComputeOutcomeData,
|
|
7
|
+
ComputeStatus,
|
|
8
|
+
VersionedComputeEngine,
|
|
9
9
|
} from "./compute-types";
|
|
10
10
|
export type {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
ConditionEvaluationCause,
|
|
12
|
+
ConditionEvaluationOptions,
|
|
13
|
+
ConditionEvaluationReport,
|
|
14
|
+
ConditionEvaluationReportLevel,
|
|
15
|
+
ConditionEvaluationReportTag,
|
|
16
|
+
ConditionEvaluatorReporter,
|
|
17
17
|
} from "./condition-evaluator-reporter";
|
|
18
18
|
export { ComputeEngineRegistry } from "./compute-engine-registry";
|
|
19
19
|
export { ComputeEvaluatorRegistry } from "./compute-evaluator-registry";
|
|
@@ -21,28 +21,28 @@ export { ComputeRegistry } from "./compute-registry";
|
|
|
21
21
|
export { GateEngineRegistry } from "./gate-engine-registry";
|
|
22
22
|
export type { GatePayload, GatePayloadV1 } from "./gate-payload";
|
|
23
23
|
export type {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
GateOutcome,
|
|
25
|
+
GateOutcomeData,
|
|
26
|
+
GateStatus,
|
|
27
|
+
GateTraceLeafSnapshot,
|
|
28
|
+
GateTraceNodeSnapshot,
|
|
29
|
+
GateViolationTrace,
|
|
30
|
+
PolicyContext,
|
|
31
|
+
PolicyViolation,
|
|
32
|
+
VersionedGateEngine,
|
|
33
33
|
} from "./gate-types";
|
|
34
34
|
export {
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
ComputePayloadParsers,
|
|
36
|
+
ComputePayloadParserRegistry,
|
|
37
37
|
} from "./parse-compute-payload";
|
|
38
38
|
export type { ComputePayloadParser } from "./parse-compute-payload";
|
|
39
39
|
export {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
GatePayloadParsers,
|
|
41
|
+
GatePayloadParserRegistry,
|
|
42
42
|
} from "./parse-gate-payload";
|
|
43
43
|
export type { GatePayloadParser } from "./parse-gate-payload";
|
|
44
44
|
export type {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
ComputeDecisionTablePayload,
|
|
46
|
+
ComputeDecisionTableRule,
|
|
47
|
+
ComputeParamsPayload,
|
|
48
48
|
} from "./v1/compute";
|
|
@@ -5,67 +5,73 @@ import type { ComputePayload } from "./compute-payload";
|
|
|
5
5
|
import { ComputePayloadSchemaV1 } from "./v1/compute/compute-payload.schema";
|
|
6
6
|
|
|
7
7
|
export type ComputePayloadParser = (
|
|
8
|
-
|
|
8
|
+
payload: unknown,
|
|
9
9
|
) => ResultType<ComputePayload, string>;
|
|
10
10
|
|
|
11
11
|
export class ComputePayloadParserRegistry {
|
|
12
|
-
|
|
12
|
+
private readonly parsers = new Map<number, ComputePayloadParser>();
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
register(payloadSchemaVersion: number, parser: ComputePayloadParser): void {
|
|
15
|
+
this.parsers.set(payloadSchemaVersion, parser);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get(payloadSchemaVersion: number): ComputePayloadParser | undefined {
|
|
19
|
+
return this.parsers.get(payloadSchemaVersion);
|
|
20
|
+
}
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
22
|
+
parse(payloadSchemaVersion: number, payload: unknown) {
|
|
23
|
+
const parser = this.parsers.get(payloadSchemaVersion);
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
if (parser === undefined) {
|
|
26
|
+
return Result.err(
|
|
27
|
+
`No compute payload parser registered for schema version "${payloadSchemaVersion}"`,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
return Result.err(
|
|
27
|
-
`No compute payload parser registered for schema version "${payloadSchemaVersion}"`,
|
|
28
|
-
);
|
|
31
|
+
return parser(payload);
|
|
29
32
|
}
|
|
30
|
-
|
|
31
|
-
return parser(payload);
|
|
32
|
-
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export class ComputePayloadParsers {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
private static readonly registry = new ComputePayloadParserRegistry();
|
|
37
|
+
private static defaultsRegistered = false;
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
// Registers the built-in v1 parser lazily, the first time the default
|
|
40
|
+
// dispatcher is touched. Done here — rather than as a top-level module
|
|
41
|
+
// statement — so the package's `"sideEffects": false` flag stays honest and
|
|
42
|
+
// a tree-shaking bundler cannot drop the v1 registration and leave the
|
|
43
|
+
// compute engine unable to parse v1 payloads at runtime.
|
|
44
|
+
private static ensureDefaults(): void {
|
|
45
|
+
if (ComputePayloadParsers.defaultsRegistered) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
ComputePayloadParsers.defaultsRegistered = true;
|
|
49
|
+
ComputePayloadParsers.registry.register(
|
|
50
|
+
1,
|
|
51
|
+
ComputePayloadSchemaV1.parse,
|
|
52
|
+
);
|
|
47
53
|
}
|
|
48
|
-
ComputePayloadParsers.defaultsRegistered = true;
|
|
49
|
-
ComputePayloadParsers.registry.register(1, ComputePayloadSchemaV1.parse);
|
|
50
|
-
}
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
static register(
|
|
56
|
+
payloadSchemaVersion: number,
|
|
57
|
+
parser: ComputePayloadParser,
|
|
58
|
+
): void {
|
|
59
|
+
ComputePayloadParsers.ensureDefaults();
|
|
60
|
+
ComputePayloadParsers.registry.register(payloadSchemaVersion, parser);
|
|
61
|
+
}
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
static get(payloadSchemaVersion: number): ComputePayloadParser | undefined {
|
|
64
|
+
ComputePayloadParsers.ensureDefaults();
|
|
65
|
+
return ComputePayloadParsers.registry.get(payloadSchemaVersion);
|
|
66
|
+
}
|
|
64
67
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
static parse(payloadSchemaVersion: number, payload: unknown) {
|
|
69
|
+
ComputePayloadParsers.ensureDefaults();
|
|
70
|
+
return ComputePayloadParsers.registry.parse(
|
|
71
|
+
payloadSchemaVersion,
|
|
72
|
+
payload,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
export type { ComputePayload };
|
|
@@ -5,64 +5,64 @@ import type { GatePayload } from "./gate-payload";
|
|
|
5
5
|
import { GatePayloadSchemaV1 } from "./v1/gate/gate-v1-payload.schema";
|
|
6
6
|
|
|
7
7
|
export type GatePayloadParser = (
|
|
8
|
-
|
|
8
|
+
payload: unknown,
|
|
9
9
|
) => ResultType<GatePayload, string>;
|
|
10
10
|
|
|
11
11
|
export class GatePayloadParserRegistry {
|
|
12
|
-
|
|
12
|
+
private readonly parsers = new Map<number, GatePayloadParser>();
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
register(engineVersion: number, parser: GatePayloadParser): void {
|
|
15
|
+
this.parsers.set(engineVersion, parser);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get(engineVersion: number): GatePayloadParser | undefined {
|
|
19
|
+
return this.parsers.get(engineVersion);
|
|
20
|
+
}
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
22
|
+
parse(engineVersion: number, payload: unknown) {
|
|
23
|
+
const parser = this.parsers.get(engineVersion);
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
if (parser === undefined) {
|
|
26
|
+
return Result.err(
|
|
27
|
+
`No gate payload parser registered for engine version "${engineVersion}"`,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
return Result.err(
|
|
27
|
-
`No gate payload parser registered for engine version "${engineVersion}"`,
|
|
28
|
-
);
|
|
31
|
+
return parser(payload);
|
|
29
32
|
}
|
|
30
|
-
|
|
31
|
-
return parser(payload);
|
|
32
|
-
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export class GatePayloadParsers {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
private static readonly registry = new GatePayloadParserRegistry();
|
|
37
|
+
private static defaultsRegistered = false;
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
// Registers the built-in v1 parser lazily, the first time the default
|
|
40
|
+
// dispatcher is touched. Done here — rather than as a top-level module
|
|
41
|
+
// statement — so the package's `"sideEffects": false` flag stays honest and
|
|
42
|
+
// a tree-shaking bundler cannot drop the v1 registration and leave the gate
|
|
43
|
+
// engine unable to parse v1 payloads at runtime.
|
|
44
|
+
private static ensureDefaults(): void {
|
|
45
|
+
if (GatePayloadParsers.defaultsRegistered) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
GatePayloadParsers.defaultsRegistered = true;
|
|
49
|
+
GatePayloadParsers.registry.register(1, GatePayloadSchemaV1.parse);
|
|
47
50
|
}
|
|
48
|
-
GatePayloadParsers.defaultsRegistered = true;
|
|
49
|
-
GatePayloadParsers.registry.register(1, GatePayloadSchemaV1.parse);
|
|
50
|
-
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
static register(engineVersion: number, parser: GatePayloadParser): void {
|
|
53
|
+
GatePayloadParsers.ensureDefaults();
|
|
54
|
+
GatePayloadParsers.registry.register(engineVersion, parser);
|
|
55
|
+
}
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
static get(engineVersion: number): GatePayloadParser | undefined {
|
|
58
|
+
GatePayloadParsers.ensureDefaults();
|
|
59
|
+
return GatePayloadParsers.registry.get(engineVersion);
|
|
60
|
+
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
static parse(engineVersion: number, payload: unknown) {
|
|
63
|
+
GatePayloadParsers.ensureDefaults();
|
|
64
|
+
return GatePayloadParsers.registry.parse(engineVersion, payload);
|
|
65
|
+
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export type { GatePayload };
|
|
@@ -4,9 +4,9 @@ import { Result } from "../../../../result/result";
|
|
|
4
4
|
import type { ComputePayloadV1 as ComputePayload } from "./compute-payload.schema";
|
|
5
5
|
import { DecisionTableResolverV1 } from "./resolve-decision-table-v1";
|
|
6
6
|
import type {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
ComputeEvaluator,
|
|
8
|
+
ComputeOutcome,
|
|
9
|
+
VersionedComputeEngine,
|
|
10
10
|
} from "../../compute-types";
|
|
11
11
|
import type { PolicyContext } from "../../gate-types";
|
|
12
12
|
|
|
@@ -15,41 +15,43 @@ import type { PolicyContext } from "../../gate-types";
|
|
|
15
15
|
const COMPUTE_ENGINE_VERSION = 1;
|
|
16
16
|
|
|
17
17
|
export class ComputeEngineV1 implements VersionedComputeEngine {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
constructor(params: { readonly coreConfig?: CoreConfig } = {}) {
|
|
22
|
-
this.coreConfig = params.coreConfig ?? coreConfig;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Evaluates an already-parsed ComputePayload against a context.
|
|
27
|
-
* Pure function — no side effects.
|
|
28
|
-
*
|
|
29
|
-
* For `params`: forwards `payload.data` directly to the evaluator.
|
|
30
|
-
* For `decision-table`: evaluates the rules in order and passes the `result`
|
|
31
|
-
* of the first one that satisfies its conditions, or `default` if none match.
|
|
32
|
-
*
|
|
33
|
-
* The evaluator is responsible for validating and transforming the final value.
|
|
34
|
-
*/
|
|
35
|
-
evaluate(
|
|
36
|
-
payload: ComputePayload,
|
|
37
|
-
context: PolicyContext,
|
|
38
|
-
evaluator: ComputeEvaluator,
|
|
39
|
-
): Result<ComputeOutcome, string> {
|
|
40
|
-
if (payload.type === "params") {
|
|
41
|
-
return evaluator.evaluate(payload.data, context);
|
|
42
|
-
}
|
|
18
|
+
readonly version = COMPUTE_ENGINE_VERSION;
|
|
19
|
+
private readonly coreConfig: CoreConfig;
|
|
43
20
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
context,
|
|
47
|
-
this.coreConfig.getConditionEvaluationOptions(COMPUTE_ENGINE_VERSION),
|
|
48
|
-
);
|
|
49
|
-
if (resolvedResult.isErr()) {
|
|
50
|
-
return Result.err(resolvedResult.errorOrNull()!);
|
|
21
|
+
constructor(params: { readonly coreConfig?: CoreConfig } = {}) {
|
|
22
|
+
this.coreConfig = params.coreConfig ?? coreConfig;
|
|
51
23
|
}
|
|
52
24
|
|
|
53
|
-
|
|
54
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Evaluates an already-parsed ComputePayload against a context.
|
|
27
|
+
* Pure function — no side effects.
|
|
28
|
+
*
|
|
29
|
+
* For `params`: forwards `payload.data` directly to the evaluator.
|
|
30
|
+
* For `decision-table`: evaluates the rules in order and passes the `result`
|
|
31
|
+
* of the first one that satisfies its conditions, or `default` if none match.
|
|
32
|
+
*
|
|
33
|
+
* The evaluator is responsible for validating and transforming the final value.
|
|
34
|
+
*/
|
|
35
|
+
evaluate(
|
|
36
|
+
payload: ComputePayload,
|
|
37
|
+
context: PolicyContext,
|
|
38
|
+
evaluator: ComputeEvaluator,
|
|
39
|
+
): Result<ComputeOutcome, string> {
|
|
40
|
+
if (payload.type === "params") {
|
|
41
|
+
return evaluator.evaluate(payload.data, context);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const resolvedResult = DecisionTableResolverV1.resolve(
|
|
45
|
+
payload,
|
|
46
|
+
context,
|
|
47
|
+
this.coreConfig.getConditionEvaluationOptions(
|
|
48
|
+
COMPUTE_ENGINE_VERSION,
|
|
49
|
+
),
|
|
50
|
+
);
|
|
51
|
+
if (resolvedResult.isErr()) {
|
|
52
|
+
return Result.err(resolvedResult.errorOrNull()!);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return evaluator.evaluate(resolvedResult.getOrNull()!, context);
|
|
56
|
+
}
|
|
55
57
|
}
|
|
@@ -8,68 +8,70 @@ import type { ConditionNode } from "../condition-types";
|
|
|
8
8
|
// ─── Pattern 1: Params ──────────────────────────────────────────────────────
|
|
9
9
|
|
|
10
10
|
export interface ComputeParamsPayload {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
readonly type: "params";
|
|
12
|
+
readonly data: Readonly<Record<string, unknown>>;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
// ─── Pattern 2: Decision table ──────────────────────────────────────────────
|
|
16
16
|
|
|
17
17
|
export interface ComputeDecisionTableRule<R = unknown> {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
readonly conditions: ConditionNode;
|
|
19
|
+
readonly result: R;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export interface ComputeDecisionTablePayload<R = unknown> {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
readonly type: "decision-table";
|
|
24
|
+
readonly rules: readonly ComputeDecisionTableRule<R>[];
|
|
25
|
+
readonly default: R;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// ─── Union ──────────────────────────────────────────────────────────────────
|
|
29
29
|
|
|
30
30
|
export type ComputePayloadV1 =
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
| ComputeDecisionTablePayload<unknown>
|
|
32
|
+
| ComputeParamsPayload;
|
|
33
33
|
|
|
34
34
|
// ─── Zod schemas ────────────────────────────────────────────────────────────
|
|
35
35
|
|
|
36
36
|
const computeDecisionTableRuleSchema = z.object({
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
conditions: conditionNodeSchema,
|
|
38
|
+
result: z.unknown(),
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
export class ComputePayloadSchemaV1 {
|
|
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
|
-
|
|
42
|
+
static readonly schema = z.union([
|
|
43
|
+
z
|
|
44
|
+
.object({
|
|
45
|
+
type: z.literal("decision-table"),
|
|
46
|
+
rules: z.array(computeDecisionTableRuleSchema).min(1),
|
|
47
|
+
default: z.unknown(),
|
|
48
|
+
})
|
|
49
|
+
.strict(),
|
|
50
|
+
z
|
|
51
|
+
.object({
|
|
52
|
+
type: z.literal("params"),
|
|
53
|
+
data: z.record(z.string(), z.unknown()),
|
|
54
|
+
})
|
|
55
|
+
.strict(),
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
static parse(payload: unknown): Result<ComputePayloadV1, string> {
|
|
59
|
+
const parsed = ComputePayloadSchemaV1.schema.safeParse(payload);
|
|
60
|
+
if (!parsed.success) {
|
|
61
|
+
const details = parsed.error.issues
|
|
62
|
+
.map((issue) => {
|
|
63
|
+
const path = issue.path.join(".");
|
|
64
|
+
return path.length > 0
|
|
65
|
+
? `${path}: ${issue.message}`
|
|
66
|
+
: issue.message;
|
|
67
|
+
})
|
|
68
|
+
.join("; ");
|
|
69
|
+
|
|
70
|
+
return Result.err(`Invalid compute payload: ${details}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return Result.ok(parsed.data as ComputePayloadV1);
|
|
69
74
|
}
|
|
70
|
-
|
|
71
|
-
return Result.ok(parsed.data as ComputePayloadV1);
|
|
72
|
-
}
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
export const computePayloadSchema = ComputePayloadSchemaV1.schema;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export { ComputeEngineV1 } from "./compute-engine-v1";
|
|
2
2
|
export type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
ComputeDecisionTablePayload,
|
|
4
|
+
ComputeDecisionTableRule,
|
|
5
|
+
ComputeParamsPayload,
|
|
6
|
+
ComputePayloadV1,
|
|
7
7
|
} from "./compute-payload.schema";
|
|
8
8
|
export {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
computePayloadSchema,
|
|
10
|
+
ComputePayloadSchemaV1,
|
|
11
11
|
} from "./compute-payload.schema";
|
|
12
12
|
export { DecisionTableResolverV1 } from "./resolve-decision-table-v1";
|
|
@@ -8,47 +8,49 @@ import type { ComputeDecisionTablePayload } from "./compute-payload.schema";
|
|
|
8
8
|
const COMPUTE_CONDITION_EVAL_FAILED_TAG = "COMPUTE_CONDITION_EVAL_FAILED";
|
|
9
9
|
|
|
10
10
|
export class DecisionTableResolverV1 {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
for (const rule of this.payload.rules) {
|
|
28
|
-
const conditionResult = evaluator.evaluate(rule.conditions);
|
|
29
|
-
if (conditionResult.isErr()) {
|
|
30
|
-
return this.wrapConditionEvaluationError(
|
|
31
|
-
conditionResult.errorOrNull()!,
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly payload: ComputeDecisionTablePayload,
|
|
13
|
+
private readonly context: Record<string, unknown>,
|
|
14
|
+
private readonly conditionEvaluationOptions: ConditionEvaluationOptions,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
private wrapConditionEvaluationError(
|
|
18
|
+
error: string,
|
|
19
|
+
): Result<unknown, string> {
|
|
20
|
+
return Result.err(`${COMPUTE_CONDITION_EVAL_FAILED_TAG}: ${error}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
resolve(): Result<unknown, string> {
|
|
24
|
+
const evaluator = new ConditionEvaluatorV1(
|
|
25
|
+
this.context,
|
|
26
|
+
this.conditionEvaluationOptions,
|
|
32
27
|
);
|
|
33
|
-
}
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
for (const rule of this.payload.rules) {
|
|
30
|
+
const conditionResult = evaluator.evaluate(rule.conditions);
|
|
31
|
+
if (conditionResult.isErr()) {
|
|
32
|
+
return this.wrapConditionEvaluationError(
|
|
33
|
+
conditionResult.errorOrNull()!,
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (conditionResult.getOrNull()) {
|
|
38
|
+
return Result.ok(rule.result);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return Result.ok(this.payload.default);
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
conditionEvaluationOptions,
|
|
52
|
-
).resolve();
|
|
53
|
-
}
|
|
45
|
+
static resolve(
|
|
46
|
+
payload: ComputeDecisionTablePayload,
|
|
47
|
+
context: Record<string, unknown>,
|
|
48
|
+
conditionEvaluationOptions: ConditionEvaluationOptions,
|
|
49
|
+
): Result<unknown, string> {
|
|
50
|
+
return new DecisionTableResolverV1(
|
|
51
|
+
payload,
|
|
52
|
+
context,
|
|
53
|
+
conditionEvaluationOptions,
|
|
54
|
+
).resolve();
|
|
55
|
+
}
|
|
54
56
|
}
|