@cullet/erp-core 1.0.9 → 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.
@@ -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()) {