Skip to content

API Overview

SymbolPurposeExecution modeCommon gotcha
createWard()Compile immutable ordered rulesSyncFirst match wins
allow() / deny()Create role-conditioned rulesSyncOne rule is produced per action
predicateCompose typed synchronous conditionsSyncAsync results throw
matchesPattern()Match exact and wildcard valuesSyncposts:* does not match posts
patternCovers()Compare pattern coverageSyncIt does not inspect conditions

Package Entry Point

ImportPurpose
@vielzeug/wardAll runtime APIs, errors, constants, and public types

Core API

createWard()

ts
function createWard<Action extends string, Resource extends string, Attributes extends WardAttributes>(
  rules?: readonly (WardRule<Action, Resource, Attributes> | readonly WardRule<Action, Resource, Attributes>[])[],
): Ward<Action, Resource, Attributes>

Returns an immutable ordered policy. Nested rule arrays are flattened once. Rules, declarative attributes, and bound principals are snapshotted.

ParameterTypeDescription
rulesreadonly (WardRule | readonly WardRule[])[]Rules in first-match order

Returns: Ward<Action, Resource, Attributes>.

ts
import { allow, createWard } from '@vielzeug/ward';

const ward = createWard<'read', 'posts'>([allow('viewer', 'posts', ['read'])]);
MethodReturnsBehavior
decide(input)WardDecisionEvaluates and emits one decision event
checkAll(inputs)WardDecision[]Evaluates each input in order
allowedActions(input)Action[]Deduplicates and filters known actions without emitting events
forPrincipal(principal?)BoundWardBinds an immutable principal snapshot
tap(handler, options?)() => voidObserves decisions; supports AbortSignal
rulesreadonly WardRule[]Immutable compiled rules

allow() and deny()

ts
allow<Action, Resource, Attributes>(role, resource, actions, options?): WardRule[]
deny<Action, Resource, Attributes>(role, resource, actions, options?): WardRule[]

Return one role-conditioned rule per action.

ParameterTypeDescription
rolestring | readonly string[]Role, role alternatives, ANONYMOUS, or WILDCARD
resourceWardPattern<Resource>Exact or wildcard resource
actionsreadonly WardPattern<Action>[]Exact or wildcard actions
options.whenWardCondition<Attributes>Additional synchronous condition

Returns: WardRule<Action, Resource, Attributes>[].

ts
import { allow, deny, WILDCARD } from '@vielzeug/ward';

const rules = [deny('blocked', WILDCARD, [WILDCARD]), allow(['editor', 'admin'], 'posts', ['read'])];

predicate

ts
predicate.hasRole<Attributes>(role)
predicate.owns<Attributes>(attribute)
predicate.and<Attributes>(...conditions)
predicate.or<Attributes>(...conditions)
predicate.not<Attributes>(condition)

Returns typed WardCondition functions. owns() accepts only a string key from the selected attribute type.


Pattern helpers

ts
matchesPattern(pattern: string, value: string): boolean
patternCovers(broad: string, narrow: string): boolean

matchesPattern() supports exact values, *, and namespace wildcards such as posts:*. patternCovers() compares those pattern sets.

Types

ts
type WardAttributeValue =
  | boolean
  | number
  | string
  | null
  | readonly WardAttributeValue[]
  | { readonly [key: string]: WardAttributeValue };

type WardAttributes = Readonly<Record<string, WardAttributeValue>>;
type WardPattern<Value extends string> = Value | typeof WILDCARD | `${string}:*`;
ts
type UserPrincipal = Readonly<{
  attributes?: WardAttributes;
  id: string;
  roles: readonly string[];
}>;

type Principal = UserPrincipal | null;
ts
type WardConditionInput<Attributes extends WardAttributes> = Readonly<{
  attributes?: Attributes;
  principal: Principal;
}>;

type WardCondition<Attributes extends WardAttributes> = (
  input: WardConditionInput<Attributes>,
) => boolean;
ts
type WardRule<Action extends string, Resource extends string, Attributes extends WardAttributes> = Readonly<{
  action: WardPattern<Action>;
  attributes?: Attributes;
  condition?: WardCondition<Attributes>;
  effect: 'allow' | 'deny';
  resource: WardPattern<Resource>;
}>;
ts
type WardDecisionInput<Action extends string, Resource extends string, Attributes extends WardAttributes> = Readonly<{
  action: Action;
  attributes?: Attributes;
  principal?: Principal;
  resource: Resource;
}>;
ts
type WardDecision<Action extends string, Resource extends string, Attributes extends WardAttributes> =
  | { effect: 'allow' | 'deny'; matched: true; reason: string; rule: WardRule<Action, Resource, Attributes> }
  | { effect: 'deny'; matched: false; reason: string; rule?: never };
ts
type WardEvent<Action extends string, Resource extends string, Attributes extends WardAttributes> = Readonly<{
  decision: WardDecision<Action, Resource, Attributes>;
  input: WardDecisionInput<Action, Resource, Attributes> & { principal: Principal };
  type: 'decision';
}>;

BoundWard, WardAllowedActionsInput, BoundWardAllowedActionsInput, and BoundWardDecisionInput expose the corresponding principal-bound method contracts.

Errors

ErrorTriggerNotable properties
WardErrorBase for Ward-originated errorsStandard cause support
WardConfigErrorInvalid rules, principals, inputs, or attribute valuesConfiguration message with field path
WardConditionErrorThrown, async, or non-boolean condition resultruleIndex, cause