Version v2.0.0 Size 2.7 KB gzip Dependencies Zero dependencies
Why Ward?
Ward keeps authorization policies declarative and decision ordering deterministic. Define rules once, then explain or trace every permission decision without embedding role checks across handlers.
ts
// Before
const canUpdate = user.roles.includes('editor') && post.authorId === user.id;
// After
import { createWard, owns } from '@vielzeug/ward';
const ward = createWard([
{ role: 'editor', resource: 'posts', action: 'update', effect: 'allow', when: owns('authorId') },
]);
const decision = ward.explain({ principal: user, resource: 'posts', action: 'update', data: post });
const canUpdate = decision.allowed;| Feature | Ward | CASL | AccessControl |
|---|---|---|---|
| Bundle size | 2.7 KB | Larger policy engine | Larger policy engine |
| Zero dependencies | |||
| Deterministic precedence | Priority, specificity, deny, order | Rule-dependent | Role-grant dependent |
| Decision tracing | trace() candidates and winner | Manual inspection | Manual inspection |
Use Ward when your application needs typed role/resource/action policies with explainable, deterministic outcomes.
Consider framework-specific authorization when your application only needs one framework's built-in route or component guard layer.
Installation
sh
pnpm add @vielzeug/wardsh
npm install @vielzeug/wardsh
yarn add @vielzeug/wardQuick Start
Create a small policy and handle both allowed and denied decisions at the request boundary.
ts
import { createWard } from '@vielzeug/ward';
const ward = createWard([
{ role: 'viewer', resource: 'posts', action: 'read', effect: 'allow' },
{ role: 'editor', resource: 'posts', action: 'update', effect: 'allow' },
]);
const decision = ward.explain({
principal: { id: 'u1', roles: ['editor'] },
resource: 'posts',
action: 'update',
});
if (decision.allowed) console.log('Update post');
else console.log(decision.reason);Features
createWard()creates immutable typed policy instances.allow(),deny(), andruleFor()build role/resource/action rules.WILDCARDandANONYMOUSmodel broad or unauthenticated access explicitly.owns()andpredicateconstrain rules with synchronous request data.explain(),trace(), anddetectConflicts()make policy decisions diagnosable.forUser()creates a principal-bound view for repeated checks.checkAll()evaluates multiple resource/action pairs in one call.