@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)
- 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 byRuleEngineuntil 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…
- engine — (no submodules)- operators-internal — `compareValues(actual, operato…
- operators-internal —
compareValues(actual, operator, expected)is the built-in comparison dispatcher used byRuleEngineuntil 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 byRuleEngineuntil 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 byRuleEngineuntil 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 byRuleEngineuntil 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—RuleContextbuilder, dot-path / array-index field resolver, request-context derivationbuilder—RuleBuilder+FieldBuilderfluent DSL + factory functionsengine—RuleEnginewith evaluate / evaluateAll / evaluateRuleset / check + plugin registrationoperators—OperatorRegistry+ 33 built-in operator definitionsactions—Action/ActionRegistry/ActionExecutor+ 4 built-in handlersevents—EventBus+HookManagerwith priority hooks andwaitForvalidators/schema— recursive JSON-schema-like validatorvalidators/field— chainable field validator with 12 presetsvalidators/custom— named validators + registry + 11 built-ins + 5 parameterised factoriesserializer— round-trip JSON with function-placeholder strategyoptimizer— AST optimiser (flatten / dedupe / simplify / sort) + analyticserrors—RulesError+ 24-code registryotel— lazy OTel instrument surface- Constants —
constants.md
Internal references
- Engine internal compare dispatcher — bridges into the operator surface
- Type guards —
isConditionRule,isLogicalRule,isGroupRule,isCustomRule,isComputedRule
Conventions
- Every public method validates input via Zod and raises
RulesErrorwith a typed code on rejection. AbortSignalis threaded through every async path; pre-aborted signals short-circuit before work begins.Clock/Rng/LoggerLikeare injectable per CLAUDE.md "no module-scopeDate.now/Math.random" rule.- 100% test coverage; sibling
.mdper implementation file ≥ 200 words. - Tests import runner primitives from
@suaveplan/testing/runnerexclusively (no directvitest/bun:test). - No
export *in feature barrels — every public symbol is named explicitly.
See also
@suaveplan/rules-hono— Hono middleware wrapping this package.