Rule server (HTTP)
@yarlisaisolutions/rule-cascade-server: a stateless HTTP service that serves manifests and bundles and evaluates operations.
The rule server implements the evaluation API of
spec/v1/rule-evaluation.openapi.yaml.
Use it for callers that cannot embed a runtime. It keeps nothing between requests, so any number of
replicas can run behind a load balancer.
Supported versions: Node.js 20 or later (engines), the same as the TypeScript runtime it is
built on. The container image is node:22-alpine; CI builds it and smoke-tests it.
Install from the repository
git clone https://github.com/YarlisAISolutions/rule-cascade.git && cd rule-cascade
npm ci && npm run build
RULE_SERVER_TOKEN=$(openssl rand -hex 32) RULES_DIR=examples/contracts node packages/server/dist/main.js| Variable | Meaning | Default |
|---|---|---|
RULES_DIR | Directory with *.ruleset.yaml / .yml / .json sources (compiled at start-up) and *.bundle.json bundles | ./rules |
PORT | Listen port | 8080 |
RULE_SERVER_TOKEN | Bearer token for evaluations, the server manifest, bundles and server-only rule details | see below |
DRAIN_SECONDS | Time between "not ready" and shutdown on SIGTERM | 5 |
Always set RULE_SERVER_TOKEN
POST /evaluations evaluates whatever actor the caller sends, and the server manifest and the
bundle reveal server-only rules. The token is required: the server exits with status 1 at start-up without RULE_SERVER_TOKEN,
unless RULE_SERVER_ALLOW_OPEN=1 is set explicitly for development on a private network. The client
manifest, the ruleset list and the health probes stay public. The
package README always describes the behaviour of the code it ships with.
Endpoints
| Method and path | Purpose | Needs the token |
|---|---|---|
GET /healthz | Liveness | no |
GET /readyz | Readiness; 503 while draining | no |
GET /rulesets?scope= | List rulesets | no |
GET /rulesets/{id}/manifest?channel=client | Client-safe manifest, with ETag | no |
GET /rulesets/{id}/manifest?channel=server | Full manifest for backend runtimes | yes |
GET /rulesets/{id}/bundle | The compiled bundle, with ETag | yes |
GET /rulesets/{id}/rules/{ruleId} | One resolved rule | server-only rules: yes |
POST /evaluations | Evaluate an operation | yes |
Evaluate
The body is the evaluation request plus ruleset, and optionally version and channel:
curl -s localhost:8080/evaluations -H "Authorization: Bearer $RULE_SERVER_TOKEN" \
-H 'Content-Type: application/json' -d '{
"ruleset": "acme.payments.transfer", "entity": "Transfer", "operation": "create",
"data": {"type": "international", "amount": 500, "currency": "USD", "memo": "gift",
"beneficiary": {"name": "X", "country": "KP", "swiftCode": "ABCDKPPY"}}}'
# {"decision":"deny","findings":[{"code":"ORG-TRF-001","message":"Transfers to KP are not permitted.", ...}], ...}The answer is the evaluation result, with HTTP 200 whatever the decision: the caller acts on
decision.
Errors
| Status | When |
|---|---|
400 | A body that is not an evaluation request; the problem document's title says what is wrong, for example 'view' must be an object |
401 | A protected endpoint without Authorization: Bearer <token> |
404 | An unknown ruleset or version |
503 on /readyz | Draining after SIGTERM |
| Process exits before it listens | A ruleset fails a load check or a bundle is unusable |
SIGHUP reloads RULES_DIR; if the new rules fail to load, the server logs the reason and keeps
serving the previous ones. A ruleset that uses a custom operator is served, a warning names the
missing operators, and those rules fail closed. To supply operators, embed the server with
createRuleServer(store, { token, operators }).
More
The package README has the full behaviour; production deployment is the Kubernetes playbook.