@livefolio/sdk 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2760,12 +2760,27 @@ type FeatureRef = {
2760
2760
  * - `'lt'` — strictly less than (`l < r`)
2761
2761
  * - `'gte'` — greater than or equal to (`l >= r`)
2762
2762
  * - `'lte'` — less than or equal to (`l <= r`)
2763
+ * - `'eq'` — equality. Without {@link Tolerance}, this is strict `l === r`
2764
+ * (no epsilon) — intended for comparing integer-valued features (e.g.
2765
+ * calendar features like `dayOfWeek`) against integer literals. With
2766
+ * {@link Tolerance}, this is "within the symmetric band around `r`" —
2767
+ * `true` while `l ∈ [r − tol, r + tol]`, `false` outside. State is still
2768
+ * persisted via {@link RuleTreeState} but, because entry and exit share
2769
+ * the same band edges, the per-step result is effectively stateless.
2763
2770
  */
2764
- type ComparisonOp = 'gt' | 'lt' | 'gte' | 'lte';
2771
+ type ComparisonOp = 'gt' | 'lt' | 'gte' | 'lte' | 'eq';
2765
2772
  /**
2766
- * Hysteresis band applied to a {@link Comparison} with `op: 'gt'` or `op: 'lt'`.
2767
- * Once the comparison has flipped, it will not flip back until the left operand
2768
- * exits the tolerance band around the right operand.
2773
+ * Tolerance band applied to a {@link Comparison} with `op: 'gt'`, `op: 'lt'`,
2774
+ * or `op: 'eq'`.
2775
+ *
2776
+ * For `gt` / `lt`, the band implements **hysteresis**: once the comparison
2777
+ * has flipped, it will not flip back until the left operand exits the band
2778
+ * around the right operand. Entry and exit thresholds differ.
2779
+ *
2780
+ * For `eq`, the band defines a **symmetric range** around `right`: the
2781
+ * comparison is `true` while `l ∈ [r − value, r + value]`. Entry and exit
2782
+ * share the same edges, so behavior is stateless in practice even though the
2783
+ * outcome is still recorded in {@link RuleTreeState}.
2769
2784
  *
2770
2785
  * `mode: 'absolute'` defines a ±`value` band around `right`.
2771
2786
  * `mode: 'relative'` defines a ±`value`% band (i.e. `value` is a percentage).
@@ -2774,7 +2789,7 @@ type ComparisonOp = 'gt' | 'lt' | 'gte' | 'lte';
2774
2789
  * so the runtime can persist the last-known state across rebalance periods.
2775
2790
  */
2776
2791
  type Tolerance = {
2777
- /** Half-width of the hysteresis band. */
2792
+ /** Half-width of the band. */
2778
2793
  value: number;
2779
2794
  /** `'absolute'` uses raw units; `'relative'` uses a percentage of `right`. */
2780
2795
  mode: 'absolute' | 'relative';
@@ -2809,8 +2824,9 @@ type Comparison = {
2809
2824
  /** Right-hand operand — a feature reference or a literal number. */
2810
2825
  right: FeatureRef | number;
2811
2826
  /**
2812
- * Optional hysteresis band. Requires `op` to be `'gt'` or `'lt'` and
2813
- * requires `id` to be set.
2827
+ * Optional tolerance band. Requires `op` to be `'gt'`, `'lt'`, or `'eq'`,
2828
+ * and requires `id` to be set. For `gt`/`lt` the band implements
2829
+ * hysteresis; for `eq` it defines a symmetric range around `right`.
2814
2830
  */
2815
2831
  tolerance?: Tolerance;
2816
2832
  /**
package/dist/index.js CHANGED
@@ -2565,6 +2565,8 @@ function rawCompare(op, l, r) {
2565
2565
  return l >= r;
2566
2566
  case "lte":
2567
2567
  return l <= r;
2568
+ case "eq":
2569
+ return l === r;
2568
2570
  }
2569
2571
  }
2570
2572
  function band(right, tol) {
@@ -2583,13 +2585,15 @@ function evalComparison(cond, values, state, outState) {
2583
2585
  if (cond.id === void 0) {
2584
2586
  throw new Error("evaluateRuleTree: comparison with tolerance requires id");
2585
2587
  }
2586
- if (cond.op !== "gt" && cond.op !== "lt") {
2587
- throw new Error(`evaluateRuleTree: tolerance is only supported for op gt/lt, got ${cond.op}`);
2588
+ if (cond.op !== "gt" && cond.op !== "lt" && cond.op !== "eq") {
2589
+ throw new Error(`evaluateRuleTree: tolerance is only supported for op gt/lt/eq, got ${cond.op}`);
2588
2590
  }
2589
2591
  const prev = state.get(cond.id);
2590
2592
  const { lower, upper } = band(r, cond.tolerance);
2591
2593
  let result;
2592
- if (prev === void 0) {
2594
+ if (cond.op === "eq") {
2595
+ result = l >= lower && l <= upper ? 1 : 0;
2596
+ } else if (prev === void 0) {
2593
2597
  result = rawCompare(cond.op, l, r) ? 1 : 0;
2594
2598
  } else if (cond.op === "gt") {
2595
2599
  if (prev === 1) result = l < lower ? 0 : 1;