Files
skills/docs/foundation/flow/rules/README.md
2026-05-29 08:20:56 +01:00

112 lines
17 KiB
Markdown

# @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.
<!-- begin:auto-docs -->
## Documentation tree
- [actions](./src/actions/actions.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [actions](./src/actions/actions.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs --> - operators-internal — `compareValues(actual, operato…
- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs --> - operators-internal — `compareValues(actual, operato…
- [operators-internal](./src/engine/operators-internal.md) — `compareValues(actual, operator, expected)` is the built-in comparison dispatcher used by `RuleEngine` until the dedica…
- [errors](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [rules-error](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [events](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [event-bus](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [constants](./src/constants.md) — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…
<!-- end:auto-docs --> - [actions](./src/actions/actions.md) — <!-- begin:auto-docs --> _(no submodules)_- [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_- [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- operators-internal — `compareValues(actual, operato…
- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- operators-internal — `compareValues(actual, operato…
- [operators-internal](./src/engine/operators-internal.md) — `compareValues(actual, operator, expected)` is the built-in comparison dispatcher used by `RuleEngine` until the dedica…
- [errors](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [rules-error](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [events](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_- [event-bus](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_- [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_- [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_- [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_- [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_- [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_- [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_- [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_- [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_- [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_- [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_- [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_- [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_- [constants](./src/constants.md) — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…
- [actions](./src/actions/actions.md) — <!-- begin:auto-docs --> _(no submodules)_- [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_- [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- operators-internal — `compareValues(actual, operato…
- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- operators-internal — `compareValues(actual, operato…
- [operators-internal](./src/engine/operators-internal.md) — `compareValues(actual, operator, expected)` is the built-in comparison dispatcher used by `RuleEngine` until the dedica…
- [errors](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [rules-error](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [events](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_- [event-bus](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_- [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_- [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_- [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_- [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_- [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_- [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_- [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_- [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_- [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_- [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_- [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_- [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_- [constants](./src/constants.md) — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…
- [actions](./src/actions/actions.md) — <!-- begin:auto-docs --> _(no submodules)_- [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_- [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- operators-internal — `compareValues(actual, operato…
- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_- operators-internal — `compareValues(actual, operato…
- [operators-internal](./src/engine/operators-internal.md) — `compareValues(actual, operator, expected)` is the built-in comparison dispatcher used by `RuleEngine` until the dedica…
- [errors](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [rules-error](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [events](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_- [event-bus](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_- [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_- [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_- [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_- [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_- [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_- [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_- [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_- [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_- [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_- [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_- [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_- [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_- [constants](./src/constants.md) — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…
- [actions](./src/actions/actions.md) — <!-- begin:auto-docs --> _(no submodules)_- [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_ - [builder](./src/builder/builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_ - [context](./src/context/context.md) — <!-- begin:auto-docs --> _(no submodules)_- [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_ - [engine](./src/engine/engine.md) — <!-- begin:auto-docs --> _(no submodules)_ - [operators-internal](./src/engine/operators-internal.md) — `compareValues(actual, operator, expected)` is the built-in comparison dispatcher used by `RuleEngine` until the dedica…
- [errors](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_ - [rules-error](./src/errors/rules-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [events](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_ - [event-bus](./src/events/event-bus.md) — <!-- begin:auto-docs --> _(no submodules)_- [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_ - [operators](./src/operators/operators.md) — <!-- begin:auto-docs --> _(no submodules)_- [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [optimizer](./src/optimizer/optimizer.md) — <!-- begin:auto-docs --> _(no submodules)_- [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_ - [otel](./src/otel/otel.md) — <!-- begin:auto-docs --> _(no submodules)_- [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [serializer](./src/serializer/serializer.md) — <!-- begin:auto-docs --> _(no submodules)_- [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_ - [custom](./src/validators/custom/custom.md) — <!-- begin:auto-docs --> _(no submodules)_- [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_ - [field](./src/validators/field/field.md) — <!-- begin:auto-docs --> _(no submodules)_- [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_ - [schema](./src/validators/schema/schema.md) — <!-- begin:auto-docs --> _(no submodules)_- [constants](./src/constants.md) — This module exposes the package-level constants consumed across the rules engine, validators, action executor, and even…
## Install
```bash
bun add @suaveplan/rules
```
## Quick start
```ts
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`](src/context/context.md) — `RuleContext` builder, dot-path / array-index field resolver, request-context derivation
- [`builder`](src/builder/builder.md) — `RuleBuilder` + `FieldBuilder` fluent DSL + factory functions
- [`engine`](src/engine/engine.md) — `RuleEngine` with evaluate / evaluateAll / evaluateRuleset / check + plugin registration
- [`operators`](src/operators/operators.md) — `OperatorRegistry` + 33 built-in operator definitions
- [`actions`](src/actions/actions.md) — `Action` / `ActionRegistry` / `ActionExecutor` + 4 built-in handlers
- [`events`](src/events/event-bus.md) — `EventBus` + `HookManager` with priority hooks and `waitFor`
- [`validators/schema`](src/validators/schema/schema.md) — recursive JSON-schema-like validator
- [`validators/field`](src/validators/field/field.md) — chainable field validator with 12 presets
- [`validators/custom`](src/validators/custom/custom.md) — named validators + registry + 11 built-ins + 5 parameterised factories
- [`serializer`](src/serializer/serializer.md) — round-trip JSON with function-placeholder strategy
- [`optimizer`](src/optimizer/optimizer.md) — AST optimiser (flatten / dedupe / simplify / sort) + analytics
- [`errors`](src/errors/rules-error.md) — `RulesError` + 24-code registry
- [`otel`](src/otel/otel.md) — lazy OTel instrument surface
- Constants — [`constants.md`](src/constants.md)
## Internal references
- [Engine internal compare dispatcher](src/engine/operators-internal.md) — bridges into the operator surface
- [Type guards](src/types/) — `isConditionRule`, `isLogicalRule`, `isGroupRule`, `isCustomRule`, `isComputedRule`
## 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
- [`@suaveplan/rules-hono`](../rules-hono/README.md) — Hono middleware wrapping this package.