@cullet/erp-core 1.0.10 → 1.0.11
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/dist/index.d.ts +113 -2
- package/dist/index.js +93 -1
- package/dist/index.js.map +1 -1
- package/dist/policy-service.d.ts +99 -0
- package/dist/policy-service.js +73 -0
- package/dist/policy-service.js.map +1 -1
- package/dist/validation-code.js +33 -0
- package/dist/validation-code.js.map +1 -1
- package/dist/validation-error.d.ts +202 -0
- package/dist/validation-error.js +164 -0
- package/dist/validation-error.js.map +1 -1
- package/meta.json +3 -2
- package/package.json +1 -1
- package/src/core/domain/entity.ts +71 -0
- package/src/core/domain/value-object.ts +41 -0
- package/src/core/errors/app-error.ts +33 -0
- package/src/core/errors/authorization-error.ts +43 -0
- package/src/core/errors/conflict-error.ts +69 -0
- package/src/core/errors/integration-error.ts +25 -0
- package/src/core/errors/not-found-error.ts +14 -0
- package/src/core/errors/validation-error.ts +18 -0
- package/src/core/policies/catalog/policy-catalog.ts +36 -0
- package/src/core/policies/resolver/policy-resolver.ts +10 -0
- package/src/core/policies/service/policy-service.ts +53 -0
- package/src/version.ts +1 -1
package/dist/policy-service.js
CHANGED
|
@@ -191,6 +191,15 @@ var PolicyCatalogEntry = class PolicyCatalogEntry {
|
|
|
191
191
|
* The catalog defines the universe of policies; the database cannot invent new ones.
|
|
192
192
|
*/
|
|
193
193
|
var PolicyCatalog = class {
|
|
194
|
+
/**
|
|
195
|
+
* Indexes the given entries up front into two lookups — one per exact
|
|
196
|
+
* variant, one per policy key (the "family") — and validates them eagerly:
|
|
197
|
+
* a duplicate variant or an internally inconsistent family throws here, at
|
|
198
|
+
* wiring time, so a malformed catalog fails fast at startup rather than on
|
|
199
|
+
* the first evaluation.
|
|
200
|
+
*
|
|
201
|
+
* @throws {UnexpectedError} When two entries resolve to the same variant key.
|
|
202
|
+
*/
|
|
194
203
|
constructor(entries) {
|
|
195
204
|
const families = /* @__PURE__ */ new Map();
|
|
196
205
|
const versionedMap = /* @__PURE__ */ new Map();
|
|
@@ -208,6 +217,14 @@ var PolicyCatalog = class {
|
|
|
208
217
|
this.versionedEntries = versionedMap;
|
|
209
218
|
this.entriesByKey = families;
|
|
210
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Returns the single entry for a key. Deliberately strict: if the key has
|
|
222
|
+
* more than one variant it errs rather than guessing, steering the caller to
|
|
223
|
+
* {@link getVersioned} or {@link getFamily}. Use this only when a key is
|
|
224
|
+
* known to be unambiguous.
|
|
225
|
+
*
|
|
226
|
+
* @returns `ok` with the entry, or `err` when the key is unknown or ambiguous.
|
|
227
|
+
*/
|
|
211
228
|
get(key) {
|
|
212
229
|
const familyResult = this.getFamily(key);
|
|
213
230
|
if (familyResult.isErr()) return Result.err(familyResult.errorOrNull());
|
|
@@ -217,11 +234,28 @@ var PolicyCatalog = class {
|
|
|
217
234
|
if (!entry) return Result.err(`Policy not found in catalog: "${key}"`);
|
|
218
235
|
return Result.ok(entry);
|
|
219
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Returns every variant registered under a key — the whole "family". This is
|
|
239
|
+
* the lookup the evaluation pipeline uses, since a single key may host
|
|
240
|
+
* several engine/schema variants that the resolver then chooses between.
|
|
241
|
+
*
|
|
242
|
+
* @returns `ok` with the family (always non-empty), or `err` when the key is unknown.
|
|
243
|
+
*/
|
|
220
244
|
getFamily(key) {
|
|
221
245
|
const family = this.entriesByKey.get(key);
|
|
222
246
|
if (!family) return Result.err(`Policy not found in catalog: "${key}"`);
|
|
223
247
|
return Result.ok(family);
|
|
224
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* Resolves the one entry matching an exact variant — kind plus engine and
|
|
251
|
+
* payload-schema versions. Falls back to the sole family member when a key
|
|
252
|
+
* has exactly one entry and that entry declares no explicit version
|
|
253
|
+
* selector, so unversioned single-variant policies "just work" without the
|
|
254
|
+
* caller spelling out versions.
|
|
255
|
+
*
|
|
256
|
+
* @param params - The key and the variant coordinates to match on.
|
|
257
|
+
* @returns `ok` with the matching entry, or `err` when no variant matches.
|
|
258
|
+
*/
|
|
225
259
|
getVersioned(params) {
|
|
226
260
|
const family = this.entriesByKey.get(params.key);
|
|
227
261
|
if (!family || family.length === 0) return Result.err(`Policy not found in catalog: "${params.key}"`);
|
|
@@ -236,9 +270,11 @@ var PolicyCatalog = class {
|
|
|
236
270
|
].filter((part) => part !== null).join(", ");
|
|
237
271
|
return Result.err(`Policy variant not found in catalog: "${params.key}" (${versionDetails})`);
|
|
238
272
|
}
|
|
273
|
+
/** Lists every registered variant across all keys — useful for introspection and diagnostics. */
|
|
239
274
|
list() {
|
|
240
275
|
return Array.from(this.versionedEntries.values());
|
|
241
276
|
}
|
|
277
|
+
/** Returns whether any variant is registered under the given key. */
|
|
242
278
|
has(key) {
|
|
243
279
|
return this.entriesByKey.has(key);
|
|
244
280
|
}
|
|
@@ -734,6 +770,16 @@ var PolicyAsOfResolver = class PolicyAsOfResolver {
|
|
|
734
770
|
* 5. policyVersion descending (semver — final deterministic tiebreaker)
|
|
735
771
|
*/
|
|
736
772
|
var PolicyResolver = class {
|
|
773
|
+
/**
|
|
774
|
+
* Picks the single winning definition from an already-filtered candidate
|
|
775
|
+
* list by applying the class's ordering criteria in priority order. The sort
|
|
776
|
+
* runs over a copy, so the caller's array is left untouched, and the final
|
|
777
|
+
* semver tiebreaker guarantees the winner is fully deterministic — it never
|
|
778
|
+
* depends on the order the repository returned the candidates in.
|
|
779
|
+
*
|
|
780
|
+
* @param candidates - Definitions already filtered to match key, scope, and as-of.
|
|
781
|
+
* @returns `ok` with the highest-ranked definition, or `err` when the list is empty.
|
|
782
|
+
*/
|
|
737
783
|
resolveBest(candidates) {
|
|
738
784
|
if (candidates.length === 0) return Result.err("No matching policy definition found (candidates list is empty)");
|
|
739
785
|
const sorted = [...candidates].sort((a, b) => {
|
|
@@ -815,6 +861,18 @@ var PolicyEvaluationErrors = class {
|
|
|
815
861
|
};
|
|
816
862
|
//#endregion
|
|
817
863
|
//#region src/core/policies/service/policy-service.ts
|
|
864
|
+
/**
|
|
865
|
+
* Orchestrates the end-to-end evaluation of a policy: it parses and validates
|
|
866
|
+
* the context seed, derives the as-of instant, resolves the best matching
|
|
867
|
+
* definition for the requested key/scope/version, builds the context the policy
|
|
868
|
+
* needs, and runs it through the right engine (gate or compute).
|
|
869
|
+
*
|
|
870
|
+
* The service never throws for an expected failure: every step returns a
|
|
871
|
+
* {@link Result}, and the failures are folded into a typed
|
|
872
|
+
* {@link PolicyEvaluationError} so callers branch on `isErr()` rather than
|
|
873
|
+
* catching. Telemetry is best-effort — a throwing reporter can never abort an
|
|
874
|
+
* evaluation — which keeps observability strictly side-band.
|
|
875
|
+
*/
|
|
818
876
|
var PolicyService = class {
|
|
819
877
|
#reporter;
|
|
820
878
|
constructor(params) {
|
|
@@ -838,6 +896,21 @@ var PolicyService = class {
|
|
|
838
896
|
if (!isValidDate(candidate)) return Result.err("seed.fields.now must be a valid Date when provided");
|
|
839
897
|
return Result.ok(candidate);
|
|
840
898
|
}
|
|
899
|
+
/**
|
|
900
|
+
* Evaluates a policy and returns its decision.
|
|
901
|
+
*
|
|
902
|
+
* This is the single public entry point. It delegates the actual work to the
|
|
903
|
+
* private pipeline and wraps it with telemetry: a completed or failed event
|
|
904
|
+
* is reported either way, but reporting is guarded so it can never change the
|
|
905
|
+
* outcome. The returned {@link Result} is `ok` with a
|
|
906
|
+
* {@link PolicyEvaluationResult} on success, or `err` with a typed
|
|
907
|
+
* {@link PolicyEvaluationError} describing which stage rejected the input —
|
|
908
|
+
* the method itself does not throw for expected failures.
|
|
909
|
+
*
|
|
910
|
+
* @param input - The policy key, scope chain, context version, and seed to
|
|
911
|
+
* evaluate, plus the caller's `decisionId`.
|
|
912
|
+
* @returns A `Result` carrying the decision or the evaluation error.
|
|
913
|
+
*/
|
|
841
914
|
async evaluate(input) {
|
|
842
915
|
const result = await this.#evaluate(input);
|
|
843
916
|
if (result.isErr()) {
|