ProvenPin Install

json-logic-js business rules: working versions (tested 2026-10-16)

Evaluate business rules with json-logic-js over data objects using and, or, comparisons, var defaults, in and if, plus a custom operation registered with add_operation; assert each result offline.

passed6 passed · 0 failed2026-10-16 20:33 UTC
Status
passed
Last passed
2026-10-16 20:33 UTC
Tests
6 / 6
Language
TypeScript
Runtime
node v22.23.3
pinned versions3
json-logic-js@2.0.5@types/node@26.6.5tsx@4.23.15
run it
npm install --no-audit --no-fund --ignore-scripts=false
npm test
test environment
node v22.23.3
linux 6.17.0-1022-azure
x64
runner: github-actions 38962988948

The code

Exactly the files that passed. Your agent can pull them with get_recipe("json-logic-js-rules") (install), or see them on GitHub.

package.json
{
  "name": "json-logic-js-rules",
  "private": true,
  "type": "module",
  "scripts": {
    "test": "node --import tsx --test test/*.test.ts"
  },
  "dependencies": {
    "json-logic-js": "2.0.5"
  },
  "devDependencies": {
    "@types/node": "26.6.5",
    "tsx": "4.23.15"
  }
}
src/rules.ts
import jsonLogic from "json-logic-js";

jsonLogic.add_operation("volume_discount", (quantity: number, unitPrice: number) => {
  const subtotal = quantity * unitPrice;
  if (quantity >= 100) return (subtotal * 4) / 5;
  if (quantity >= 10) return (subtotal * 9) / 10;
  return subtotal;
});

export const rules = {
  freeShipping: {
    and: [
      { ">=": [{ var: "total" }, 100] },
      { "==": [{ var: "country" }, "US"] },
    ],
  },
  needsReview: {
    or: [
      { ">=": [{ var: "total" }, 1000] },
      { in: [{ var: "country" }, ["IR", "KP"]] },
    ],
  },
  customerAge: { var: ["customer.age", 0] },
  isGiftOrder: { in: ["gift", { var: ["items", []] }] },
  shipping: {
    if: [
      { var: ["isDigital", false] },
      "digital-delivery",
      { ">=": [{ var: "total" }, 100] },
      "free-shipping",
      "paid-shipping",
    ],
  },
};

export const volumeDiscountRule = {
  volume_discount: [{ var: "quantity" }, { var: "unitPrice" }],
};

export function evaluate(rule: unknown, data: Record<string, unknown>): unknown {
  return jsonLogic.apply(rule, data);
}
test/rules.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import jsonLogic from "json-logic-js";
import { rules, volumeDiscountRule, evaluate } from "../src/rules.ts";

test("and combines comparison predicates", () => {
  assert.equal(jsonLogic.apply(rules.freeShipping, { total: 150, country: "US" }), true);
  assert.equal(jsonLogic.apply(rules.freeShipping, { total: 150, country: "CA" }), false);
  assert.equal(jsonLogic.apply(rules.freeShipping, { total: 50, country: "US" }), false);
});

test("or combines predicates and in matches array values", () => {
  assert.equal(jsonLogic.apply(rules.needsReview, { total: 1500, country: "US" }), true);
  assert.equal(jsonLogic.apply(rules.needsReview, { total: 20, country: "KP" }), true);
  assert.equal(jsonLogic.apply(rules.needsReview, { total: 20, country: "US" }), false);
});

test("var reads nested paths and falls back to a default", () => {
  assert.equal(jsonLogic.apply(rules.customerAge, { customer: { age: 30 } }), 30);
  assert.equal(jsonLogic.apply(rules.customerAge, { customer: {} }), 0);
  assert.equal(jsonLogic.apply(rules.customerAge, {}), 0);
});

test("in returns false when the array is absent", () => {
  assert.equal(evaluate(rules.isGiftOrder, { items: ["gift", "book"] }), true);
  assert.equal(evaluate(rules.isGiftOrder, { items: ["book"] }), false);
  assert.equal(evaluate(rules.isGiftOrder, {}), false);
});

test("if picks the first matching branch", () => {
  assert.equal(jsonLogic.apply(rules.shipping, { isDigital: true, total: 5 }), "digital-delivery");
  assert.equal(jsonLogic.apply(rules.shipping, { total: 150 }), "free-shipping");
  assert.equal(jsonLogic.apply(rules.shipping, { total: 20 }), "paid-shipping");
});

test("custom operation applies tiered volume discount", () => {
  assert.equal(jsonLogic.apply(volumeDiscountRule, { quantity: 120, unitPrice: 10 }), 960);
  assert.equal(jsonLogic.apply(volumeDiscountRule, { quantity: 10, unitPrice: 10 }), 90);
  assert.equal(jsonLogic.apply(volumeDiscountRule, { quantity: 3, unitPrice: 10 }), 30);
});

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.