Files
2026-05-27 23:47:53 +01:00
..
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00
2026-05-27 23:47:53 +01:00

@suaveplan/rules - Rule engine and validation system — async evaluator, fluent builder, 30 operators, schema/field/custom validators, serializer, optimizer; Zod boundaries, OTel surface, AbortSignal throughout

Summary

Universal rule engine + validation system. Comprehensive RuleEngine with async evaluation, depth limit, AbortSignal, plugin registration; fluent RuleBuilder + factory functions; 33-operator OperatorRegistry; three validator families (SchemaValidator, FieldValidator, CustomValidator); JSON serializer with function-placeholder strategy; AST optimiser (flatten / dedupe / simplify / sort); action subsystem with timeout + abort; typed event bus with priority hooks + bounded history. Zod boundaries at every public surface; OTel spans + histograms + counters from production paths; RulesError extends SuaveplanError with a 24-code registry.

Documentation tree

  • actions — (no submodules)
  • builder — (no submodules)
  • context — (no submodules)
  • engine — (no submodules) - operators-internal — `compareValues(actual, operato…
    • engine — (no submodules) - operators-internal — `compareValues(actual, operato…
    • operators-internal — compareValues(actual, operator, expected) is the built-in comparison dispatcher used by RuleEngine until the dedica…
  • errors — (no submodules)
  • events — (no submodules)
  • operators — (no submodules)
  • optimizer — (no submodules)
  • otel — (no submodules)
    • otel — (no submodules)
  • serializer — (no submodules)
  • custom — (no submodules)
  • field — (no submodules)
    • field — (no submodules)
  • schema — (no submodules)
  • constants — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…
- [actions](./src/actions/actions.md) — _(no submodules)_- [builder](./src/builder/builder.md) — _(no submodules)_- [builder](./src/builder/builder.md) — _(no submodules)_- [context](./src/context/context.md) — _(no submodules)_- [context](./src/context/context.md) — _(no submodules)_- [engine](./src/engine/engine.md) — _(no submodules)_- operators-internal — `compareValues(actual, operato…
  • engine — (no submodules)- operators-internal — `compareValues(actual, operato…
  • operators-internal — compareValues(actual, operator, expected) is the built-in comparison dispatcher used by RuleEngine until the dedica…
  • errors — (no submodules)- rules-error — (no submodules)- events — (no submodules)- event-bus — (no submodules)- operators — (no submodules)- operators — (no submodules)- optimizer — (no submodules)- optimizer — (no submodules)- otel — (no submodules)- otel — (no submodules)- serializer — (no submodules)- serializer — (no submodules)- custom — (no submodules)- custom — (no submodules)- field — (no submodules)- field — (no submodules)- schema — (no submodules)- schema — (no submodules)- constants — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…
  • actions — (no submodules)- builder — (no submodules)- builder — (no submodules)- context — (no submodules)- context — (no submodules)- engine — (no submodules)- operators-internal — `compareValues(actual, operato…
    • engine — (no submodules)- operators-internal — `compareValues(actual, operato…
    • operators-internal — compareValues(actual, operator, expected) is the built-in comparison dispatcher used by RuleEngine until the dedica…
  • errors — (no submodules)- rules-error — (no submodules)- events — (no submodules)- event-bus — (no submodules)- operators — (no submodules)- operators — (no submodules)- optimizer — (no submodules)- optimizer — (no submodules)- otel — (no submodules)- otel — (no submodules)- serializer — (no submodules)- serializer — (no submodules)- custom — (no submodules)- custom — (no submodules)- field — (no submodules)- field — (no submodules)- schema — (no submodules)- schema — (no submodules)- constants — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…
  • actions — (no submodules)- builder — (no submodules)- builder — (no submodules)- context — (no submodules)- context — (no submodules)- engine — (no submodules)- operators-internal — `compareValues(actual, operato…
    • engine — (no submodules)- operators-internal — `compareValues(actual, operato…
    • operators-internal — compareValues(actual, operator, expected) is the built-in comparison dispatcher used by RuleEngine until the dedica…
  • errors — (no submodules)- rules-error — (no submodules)- events — (no submodules)- event-bus — (no submodules)- operators — (no submodules)- operators — (no submodules)- optimizer — (no submodules)- optimizer — (no submodules)- otel — (no submodules)- otel — (no submodules)- serializer — (no submodules)- serializer — (no submodules)- custom — (no submodules)- custom — (no submodules)- field — (no submodules)- field — (no submodules)- schema — (no submodules)- schema — (no submodules)- constants — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…
  • actions — (no submodules)- builder — (no submodules) - builder — (no submodules)- context — (no submodules) - context — (no submodules)- engine — (no submodules) - engine — (no submodules) - operators-internal — compareValues(actual, operator, expected) is the built-in comparison dispatcher used by RuleEngine until the dedica…
  • errors — (no submodules) - rules-error — (no submodules)- events — (no submodules) - event-bus — (no submodules)- operators — (no submodules) - operators — (no submodules)- optimizer — (no submodules) - optimizer — (no submodules)- otel — (no submodules) - otel — (no submodules)- serializer — (no submodules) - serializer — (no submodules)- custom — (no submodules) - custom — (no submodules)- field — (no submodules) - field — (no submodules)- schema — (no submodules) - schema — (no submodules)- constants — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…

Install

bun add @suaveplan/rules

Quick start

import { context } from "@suaveplan/rules/context";
import { rule } from "@suaveplan/rules/builder";
import { RuleEngine } from "@suaveplan/rules/engine";

const policy = rule()
    .field("age").greaterThanOrEqual(18)
    .and()
    .field("region").in(["US", "CA"])
    .build();

const engine = new RuleEngine();
const result = await engine.evaluate(policy, context({ age: 21, region: "US" }));
// result.passed === true

Modules

  • context — RuleContext builder, dot-path / array-index field resolver, request-context derivation
  • builder — RuleBuilder + FieldBuilder fluent DSL + factory functions
  • engine — RuleEngine with evaluate / evaluateAll / evaluateRuleset / check + plugin registration
  • operators — OperatorRegistry + 33 built-in operator definitions
  • actions — Action / ActionRegistry / ActionExecutor + 4 built-in handlers
  • events — EventBus + HookManager with priority hooks and waitFor
  • validators/schema — recursive JSON-schema-like validator
  • validators/field — chainable field validator with 12 presets
  • validators/custom — named validators + registry + 11 built-ins + 5 parameterised factories
  • serializer — round-trip JSON with function-placeholder strategy
  • optimizer — AST optimiser (flatten / dedupe / simplify / sort) + analytics
  • errors — RulesError + 24-code registry
  • otel — lazy OTel instrument surface
  • Constants — constants.md

Internal references

Conventions

  • Every public method validates input via Zod and raises RulesError with a typed code on rejection.
  • AbortSignal is threaded through every async path; pre-aborted signals short-circuit before work begins.
  • Clock / Rng / LoggerLike are injectable per CLAUDE.md "no module-scope Date.now/Math.random" rule.
  • 100% test coverage; sibling .md per implementation file ≥ 200 words.
  • Tests import runner primitives from @suaveplan/testing/runner exclusively (no direct vitest / bun:test).
  • No export * in feature barrels — every public symbol is named explicitly.

See also