Rule Cascade
Examples

UI form (React)

A transfer form whose hidden fields, computed fee, warnings and blocked submit all come from the client manifest.

Code: examples/frontend-react (README). CI builds it on every push.

The React example: a transfer form where the SWIFT field, the fee, the warnings and the blocked submit button all come from the contract

Run it

npm ci
npm run build                                            # the runtime the example links to
npm run dev -w rule-cascade-example-frontend-react
Do thisThe contract responds with
Switch Type to InternationalThe SWIFT field appears and becomes required (state rule), and a fee is computed (compute rule)
Enter an amount of 10000 or moreA warning that blocks until you tick the acknowledgement
Enter an amount above 25000An error only a risk-officer may accept
Clear the memoA non-blocking warning

How it is built

From src/TransferForm.tsx. The form state is converted to the entity's shape, evaluated with the hook, and drawn:

/** Form state -> the entity shape the contract talks about. Empty inputs become null, not "". */
function toEntity(d: TransferDraft) {
  return {
    type: d.type,
    amount: d.amount.trim() === '' || Number.isNaN(Number(d.amount)) ? null : Number(d.amount),
    currency: d.currency,
    memo: d.memo,
    beneficiary: { name: d.name, country: d.country.toUpperCase(), swiftCode: d.swiftCode.trim() === '' ? null : d.swiftCode.trim() },
  };
}
const resolutions: Resolution[] = acknowledged.map((rule) => ({ rule, type: 'acknowledge' }));
const request: EvaluationRequest = {
  entity: 'Transfer',
  operation: 'create',
  data: toEntity(draft),
  actor: { id: 'u-1', roles: ['teller'] },
  resolutions,
};
const { result, allowed, findings, states, computed, findingsFor } = useRuleEvaluation(manifest, request);
// Field state comes from `state` rules. A field the contract does not mention keeps the app's default.
const swift = states['/beneficiary/swiftCode'] ?? {};
const fee = computed['/fee'];

The manifest is the generated src/manifest.client.json so the example runs without a backend. Against a real service, src/App.tsx notes the one change:

const client = createManifestClient({ baseUrl: '/api/rules' });
const manifest = await client.get('acme.payments.transfer');

The client manifest has 9 of the 14 rules: the four enforcement: server rules (blocked country, currency immutable, delete only drafts, four eyes) and the action rule are not in it. A client pass therefore never guarantees the server will accept.

Step by step: Add rule enforcement to a React form.

Source: site/content/docs/examples/ui-form.mdx

On this page