Version v3.0.0 Size 2.2 KB gzip Dependencies Zero dependencies
Why Ward?
Ward evaluates immutable ordered rules. The first matching rule wins; no match means deny. Typed action, resource, and attribute contracts keep role and ownership policies explicit.
Quick Start
ts
import { allow, createWard, deny, predicate, WILDCARD } from '@vielzeug/ward';
const ward = createWard([
deny('blocked', WILDCARD, [WILDCARD]),
allow('editor', 'posts', ['read', 'update'], { when: predicate.owns('authorId') }),
allow('viewer', 'posts', ['read']),
]);
const decision = ward.decide({
action: 'update',
attributes: { authorId: 'u1' },
principal: { id: 'u1', roles: ['editor'] },
resource: 'posts',
});| Feature | Ward | Inline conditionals |
|---|---|---|
| Ordered first-match policy | Manual | |
| Default deny | Manual | |
| Typed actions | Partial | |
| Ownership predicates | Manual | |
| Zero dependencies |
Features
- Ordered
allowanddenydecisions - Concise role/action rule factories
predicate.owns(),and(),or(), andnot()- Exact, namespace, and wildcard action/resource patterns
- Immutable rules, principals, and JSON-compatible attributes
- Typed batch, bound-principal, and allowed-action checks
tap()decision observability- Default deny when no rule matches
Installation
sh
pnpm add @vielzeug/wardDocumentation
See Also
- Postmaster — authorize durable job actions at application boundaries.
- Refine — consume decisions in accessible UI components.