@vielzeug/codex 2.3.1 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/data/catalog.json +0 -1886
- package/data/llms-full.txt +0 -32016
- package/data/llms.txt +0 -45
- package/data/manifest.json +0 -8
- package/data/packages/arsenal.json +0 -210
- package/data/packages/assay.json +0 -39
- package/data/packages/clockwork.json +0 -67
- package/data/packages/codex.json +0 -43
- package/data/packages/coins.json +0 -102
- package/data/packages/conduit.json +0 -60
- package/data/packages/courier.json +0 -59
- package/data/packages/dnd.json +0 -77
- package/data/packages/familiar.json +0 -40
- package/data/packages/flux.json +0 -93
- package/data/packages/focus.json +0 -37
- package/data/packages/forge.json +0 -83
- package/data/packages/gesture.json +0 -25
- package/data/packages/herald.json +0 -108
- package/data/packages/illusionist.json +0 -132
- package/data/packages/keymap.json +0 -60
- package/data/packages/ledger.json +0 -57
- package/data/packages/lingua.json +0 -68
- package/data/packages/necromancer.json +0 -50
- package/data/packages/orbit.json +0 -99
- package/data/packages/ore.json +0 -68
- package/data/packages/postmaster.json +0 -51
- package/data/packages/prism.json +0 -66
- package/data/packages/pulse.json +0 -70
- package/data/packages/refine.json +0 -12
- package/data/packages/ripple.json +0 -83
- package/data/packages/rune.json +0 -79
- package/data/packages/sandbox.json +0 -40
- package/data/packages/scout.json +0 -61
- package/data/packages/scroll.json +0 -109
- package/data/packages/sentinel.json +0 -35
- package/data/packages/sourcerer.json +0 -73
- package/data/packages/spell.json +0 -133
- package/data/packages/tempo.json +0 -81
- package/data/packages/vault.json +0 -79
- package/data/packages/ward.json +0 -114
- package/data/packages/wayfinder.json +0 -110
- package/data/refine.json +0 -11847
- package/data/search.json +0 -1582
package/data/packages/ward.json
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"apiSource": "export { allow, deny, owns, predicate, ruleFor } from './builder';\nexport { ANONYMOUS, WILDCARD } from './constants';\nexport { WardConfigError, WardError, WardPredicateError } from './errors';\nexport { createWard } from './factory';\nexport { matchesPattern, patternCovers } from './resource';\nexport type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';\n",
|
|
3
|
-
"docs": {
|
|
4
|
-
"index": "---\ntitle: Ward — Deterministic authorization for TypeScript\ndescription: Typed authorization policies with wildcard matching, deterministic precedence, and decision tracing.\npackage: ward\ncategory: auth\nkeywords: [authorization, rbac, permissions, policy, roles, wildcard, predicates]\nrelated: [wayfinder, conduit, herald]\nexports: [createWard, allow, deny, ruleFor, owns, predicate, ANONYMOUS, WILDCARD, WardError, WardConfigError, WardPredicateError, NormalizedWardRule, matchesPattern, patternCovers]\nenvironments: [browser, node, ssr, deno]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"ward\" />\n\n## Why Ward?\n\nWard keeps authorization policies declarative and decision ordering deterministic. Define rules once, then explain or trace every permission decision without embedding role checks across handlers.\n\n```ts\n// Before\nconst canUpdate = user.roles.includes('editor') && post.authorId === user.id;\n\n// After\nimport { allow, createWard, owns } from '@vielzeug/ward';\n\nconst ward = createWard([\n allow('editor', 'posts', ['update'], { when: owns('authorId') }),\n]);\n\nconst decision = ward.explain({ principal: user, resource: 'posts', action: 'update', data: post });\nconst canUpdate = decision.allowed;\n```\n\n| Feature | Ward | CASL | AccessControl |\n| ------------------------ | -------------------------------------------- | ---------------------------------------- | ---------------------------------------- |\n| Bundle size | <PackageInfo package=\"ward\" type=\"size\" /> | Larger policy engine | Larger policy engine |\n| Zero dependencies | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Deterministic precedence | Priority, specificity, deny, order | Rule-dependent | Role-grant dependent |\n| Decision tracing | `trace()` candidates and winner | Manual inspection | Manual inspection |\n\n<div class=\"decision-callout\">\n\n**Use Ward when** your application needs typed role/resource/action policies with explainable, deterministic outcomes.\n\n**Consider framework-specific authorization when** your application only needs one framework's built-in route or component guard layer.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/ward\n```\n\n```sh [npm]\nnpm install @vielzeug/ward\n```\n\n```sh [yarn]\nyarn add @vielzeug/ward\n```\n\n:::\n\n## Quick Start\n\nCreate a small policy and handle both allowed and denied decisions at the request boundary.\n\n```ts\nimport { allow, createWard } from '@vielzeug/ward';\n\nconst ward = createWard([\n allow('viewer', 'posts', ['read']),\n allow('editor', 'posts', ['update']),\n]);\n\nconst decision = ward.explain({\n principal: { id: 'u1', roles: ['editor'] },\n resource: 'posts',\n action: 'update',\n});\n\nif (decision.allowed) console.log('Update post');\nelse console.log(decision.reason);\n```\n\n## Features\n\n<div class=\"features-grid\">\n\n- `createWard()` creates immutable typed policy instances. Accepts `allow()`/`deny()` results directly — no spread needed.\n- `allow()`, `deny()`, and `ruleFor()` build role/resource/action rules.\n- `WILDCARD` and `ANONYMOUS` model broad or unauthenticated access explicitly.\n- `owns()` and `predicate` constrain rules with synchronous request data.\n- `explain()`, `trace()`, and `detectConflicts()` make policy decisions diagnosable.\n- `tap()` subscribes to decision events for logging and diagnostics.\n- `forUser()` creates a principal-bound view for repeated checks.\n- `checkAll()` evaluates multiple resource/action pairs in one call.\n\n</div>\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Examples](./examples.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Wayfinder](/wayfinder/) — route middleware can enforce Ward decisions during navigation.\n- [Conduit](/conduit/) — inject a Ward policy into application services.\n- [Herald](/herald/) — publish authorization outcomes as typed application events.\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
|
|
5
|
-
"api": "---\ntitle: Ward — API Reference\ndescription: Complete API reference for @vielzeug/ward.\n---\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Execution mode | Common gotcha |\n| --- | --- | --- | --- |\n| `createWard` | Creates immutable policy | Sync | Rules cannot be mutated after creation |\n| `allow` / `deny` / `ruleFor` | Builds policy rules | Sync | Priority wins before specificity |\n| `Ward.explain` | Returns one decision | Sync | Pass resource data for predicate rules |\n| `Ward.trace` | Inspects decision candidates | Sync | Does not fire a `decision` event |\n| `Ward.forUser` | Binds a principal | Sync | Rebind when identity or roles change |\n| `Ward.checkAll` | Batch permission checks | Sync | Pass resource data for predicate rules |\n| `Ward.allowedActions` | Filters known actions to allowed set | Sync | Does not fire a `decision` event |\n| `Ward.rulesInScope` | Lists rules matching a principal/resource | Sync | Pass data to evaluate predicates |\n| `Ward.detectConflicts` | Detects duplicate/shadowed rules | Sync | O(n²) — use `maxConflicts` for large policies |\n| `predicate.owns` / `owns` | Ownership predicate on resource data | Sync | Skipped for anonymous principals |\n| `predicate.and` / `or` / `not` | Combine predicates | Sync | All inputs must be synchronous |\n| `matchesPattern` / `patternCovers` | Test resource pattern coverage | Sync | `'*'` is the only wildcard |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/ward` | Rules, factory, predicates, pattern helpers, errors, and public types |\n\n## Core Factory\n\n### `createWard(rules, options?)`\n\n```ts\ncreateWard<TAction extends string = string, TData = unknown>(\n rules: readonly (WardRule<TAction, TData> | readonly WardRule<TAction, TData>[])[] = [],\n options?: WardOptions<TAction, TData>,\n): Ward<TAction, TData>;\n```\n\nCreates an immutable ward instance. `rules` accepts a flat mix of single rules and rule arrays — `allow()`/`deny()`/`ruleFor()` results can be passed directly without spread. Validates `onConflict` and `maxConflicts` options before compiling rules; invalid values throw `WardConfigError`.\n\n**Parameters:**\n\n| Name | Type | Description |\n| --- | --- | --- |\n| `rules` | `readonly (WardRule \\| readonly WardRule[])[]` | Rule list. Single rules and rule arrays can be mixed. |\n| `options.onConflict` | `(conflict: WardConflict) => void` | Called synchronously per conflict at creation time. |\n| `options.strict` | `boolean` | Throws `WardConfigError` on the first conflict. |\n| `options.maxConflicts` | `number` | Caps the number of conflicts returned by `detectConflicts()`. |\n\n**Returns:** `Ward<TAction, TData>` — an immutable policy instance.\n\n**Example:**\n\n```ts\nimport { allow, createWard, deny, WILDCARD } from '@vielzeug/ward';\n\nconst ward = createWard([\n allow('viewer', 'posts', ['read']),\n allow('editor', 'posts', ['update']),\n deny('blocked', WILDCARD, [WILDCARD], { priority: 100 }),\n]);\n```\n\n---\n\n## Rule Builders\n\n### `allow(role, resource, actions, options?)`\n\n```ts\nallow<TAction extends string = string, TData = unknown>(\n role: string | readonly string[],\n resource: string | typeof WILDCARD,\n actions: readonly (TAction | typeof WILDCARD)[],\n options?: { priority?: number; when?: WardPredicate<TData> },\n): WardRule<TAction, TData>[];\n```\n\nCreates one `WardRule` per action with `effect: 'allow'`. Reads naturally: \"allow editor to read/update posts\".\n\n**Returns:** `WardRule[]` — one rule per action.\n\n---\n\n### `deny(role, resource, actions, options?)`\n\n```ts\ndeny<TAction extends string = string, TData = unknown>(\n role: string | readonly string[],\n resource: string | typeof WILDCARD,\n actions: readonly (TAction | typeof WILDCARD)[],\n options?: { priority?: number; when?: WardPredicate<TData> },\n): WardRule<TAction, TData>[];\n```\n\nCreates one `WardRule` per action with `effect: 'deny'`. Reads naturally: \"deny blocked from reading posts\".\n\n**Returns:** `WardRule[]` — one rule per action.\n\n---\n\n### `ruleFor(effect, role, resource, actions, options?)`\n\n```ts\nruleFor<TAction extends string = string, TData = unknown>(\n effect: 'allow' | 'deny',\n role: string | readonly string[],\n resource: string | typeof WILDCARD,\n actions: readonly (TAction | typeof WILDCARD)[],\n options?: { priority?: number; when?: WardPredicate<TData> },\n): WardRule<TAction, TData>[];\n```\n\nLow-level factory. Prefer `allow()` or `deny()` for ergonomic rule authoring.\n\n**Returns:** `WardRule[]` — one rule per action.\n\n---\n\n## Ward Methods\n\n### `checkAll(principal, checks)`\n\n```ts\ncheckAll(\n principal: Principal,\n checks: readonly WardCheck<TAction, TData>[],\n): WardDecisionResult<TAction, TData>[];\n```\n\nEvaluates multiple resource/action pairs for one principal. Fires a `decision` event for each result via `tap()`.\n\n**Returns:** `WardDecisionResult[]` — each entry carries `action`, `resource`, and the decision.\n\n---\n\n### `explain(input)`\n\n```ts\nexplain(input: WardDecisionInput<TAction, TData>): WardDecision<TAction, TData>;\n```\n\n`WardDecisionInput`:\n\n```ts\n{\n principal: Principal;\n resource: string;\n action: TAction;\n data?: TData;\n}\n```\n\nReturns one decision. Fires a `decision` event via `tap()`.\n\n**Returns:** `WardDecision` — `{ allowed: true; rule }` or `{ allowed: false; reason: 'explicit-deny'; rule }` or `{ allowed: false; reason: 'no-matching-rule' }`.\n\n---\n\n### `trace(input)`\n\n```ts\ntrace(input: WardDecisionInput<TAction, TData>): WardTrace<TAction, TData>;\n```\n\nSame request shape as `explain()`. Returns winner + candidate list. Does not fire a `decision` event.\n\n**Returns:** `WardTrace` — `{ candidates: WardTraceCandidate[]; decision: WardDecision }`.\n\n---\n\n### `allowedActions(input)`\n\n```ts\nallowedActions(input: WardAllowedActionsInput<TAction, TData>): TAction[];\n```\n\nInput shape:\n\n```ts\n{\n principal: Principal;\n resource: string;\n knownActions: readonly TAction[];\n data?: TData;\n}\n```\n\nFilters the provided `knownActions` list to those the principal may perform. Does not fire a `decision` event.\n\n**Returns:** `TAction[]` — the subset of `knownActions` that `explain()` would allow.\n\n---\n\n### `rulesInScope(input)`\n\n```ts\nrulesInScope(input: WardRulesInScopeInput<TData>): ReadonlyArray<Readonly<NormalizedWardRule<TAction, TData>>>;\n```\n\nInput shape:\n\n```ts\n{\n principal: Principal;\n resource: string;\n data?: TData;\n}\n```\n\nLists rules matching the principal/resource pair. Pass `data` to evaluate predicate-gated matches; without it, predicate rules are skipped.\n\n**Returns:** `ReadonlyArray<Readonly<NormalizedWardRule>>` — rules in their normalized form (`role` always array, `priority` always number).\n\n---\n\n### `detectConflicts()`\n\n```ts\ndetectConflicts(): readonly WardConflict<TAction, TData>[];\n```\n\nLazily computes and caches duplicate/shadowed rule conflicts. O(n²) — use `maxConflicts` for large policies.\n\n**Returns:** `readonly WardConflict[]` — `{ kind: 'duplicate'; indexA; indexB; ruleA; ruleB }` or `{ kind: 'shadowed'; shadowedIndex; shadowedRule; shadowingIndex; shadowingRule }`.\n\n---\n\n### `forUser(principal)`\n\n```ts\nforUser(principal: UserPrincipal): BoundWard<TAction, TData>;\n```\n\nReturns a principal-bound view. `UserPrincipal` (not nullable — use `null` directly with `explain()` for anonymous).\n\n**Returns:** `BoundWard` — same methods without the `principal` argument.\n\n---\n\n## `BoundWard` Methods\n\n```ts\ntype BoundWard<TAction extends string = string, TData = unknown> = {\n allowedActions(input: BoundWardAllowedActionsInput<TAction, TData>): TAction[];\n checkAll(checks: readonly WardCheck<TAction, TData>[]): WardDecisionResult<TAction, TData>[];\n explain(input: BoundWardDecisionInput<TAction, TData>): WardDecision<TAction, TData>;\n rulesInScope(input: BoundWardRulesInScopeInput<TData>): ReadonlyArray<Readonly<NormalizedWardRule<TAction, TData>>>;\n trace(input: BoundWardDecisionInput<TAction, TData>): WardTrace<TAction, TData>;\n};\n```\n\nBound input shapes remove `principal`:\n\n```ts\n{ resource: string; action: TAction; data?: TData } // explain/trace\n{ resource: string; knownActions: readonly TAction[]; data?: TData } // allowedActions\n{ resource: string; data?: TData } // rulesInScope\n```\n\n---\n\n## Predicate Helpers\n\n### `predicate.owns(attributeKey)`\n\n```ts\npredicate.owns<TData = unknown>(\n attributeKey: [keyof TData] extends [never] ? string : keyof TData & string,\n): WardPredicate<TData>;\n```\n\nReturns a `WardPredicate` that checks whether `data[attributeKey]` matches `principal.id`. Skipped for anonymous principals — pairing `owns` with an `ANONYMOUS`-role rule produces a rule that can never match.\n\n**Returns:** `WardPredicate<TData>`.\n\n---\n\n### `predicate.and(...predicates)`\n\n```ts\npredicate.and<TData = unknown>(...preds: WardPredicate<TData>[]): WardPredicate<TData>;\n```\n\nAll predicates must return `true`.\n\n---\n\n### `predicate.or(...predicates)`\n\n```ts\npredicate.or<TData = unknown>(...preds: WardPredicate<TData>[]): WardPredicate<TData>;\n```\n\nAt least one predicate must return `true`.\n\n---\n\n### `predicate.not(predicate)`\n\n```ts\npredicate.not<TData = unknown>(pred: WardPredicate<TData>): WardPredicate<TData>;\n```\n\nInverts the given predicate.\n\n---\n\n### `owns(attributeKey)` (alias)\n\n```ts\nowns<TData = unknown>(\n attributeKey: [keyof TData] extends [never] ? string : keyof TData & string,\n): WardPredicate<TData>;\n```\n\nTop-level re-export of `predicate.owns`.\n\nPredicates run synchronously. Returning a Promise throws `WardPredicateError`.\n\n---\n\n## Pattern Helpers\n\n### `matchesPattern(pattern, value): boolean`\n\n```ts\nmatchesPattern(pattern: string, value: string): boolean;\n```\n\nTests whether `value` matches a `'*'`-wildcard `pattern`. `'*'` matches any value; an exact string matches only itself.\n\n---\n\n### `patternCovers(broad, narrow): boolean`\n\n```ts\npatternCovers(broad: string, narrow: string): boolean;\n```\n\nTests whether the `broad` pattern covers the `narrow` pattern. `'*'` covers everything; an exact string covers only itself.\n\n---\n\n## Observability\n\n### `tap(handler, options?)`\n\n```ts\ntap(\n handler: (event: WardEvent<TAction, TData>) => void,\n options?: { signal?: AbortSignal },\n): () => void;\n```\n\nSubscribes a handler to ward events. Each `explain()` and `checkAll()` decision fires a `decision` event. `trace()` and `allowedActions()` do not fire events.\n\nPass an `AbortSignal` to unsubscribe automatically; the returned function unsubscribes manually.\n\n**Returns:** `() => void` — call to unsubscribe the handler.\n\n**Example:**\n\n```ts\nconst ward = createWard(rules);\nward.tap((event) => console.debug(`ward:${event.type}`, event.decision));\n```\n\nWith a logger from `@vielzeug/rune`:\n\n```ts\nimport { createLogger } from '@vielzeug/rune';\nconst log = createLogger({ name: 'ward' });\nward.tap((event) => log.debug(event, 'ward:decision'));\n```\n\n---\n\n## Types\n\n```ts\nexport type UserPrincipal = {\n attributes?: Record<string, unknown>;\n id: string;\n roles: readonly string[];\n};\n\nexport type Principal = UserPrincipal | null;\n\nexport type RuleContext<TData = unknown> = {\n data?: TData;\n principal: UserPrincipal;\n};\n\nexport type WardPredicate<TData = unknown> = (ctx: RuleContext<TData>) => boolean;\n\nexport type WardRule<TAction extends string = string, TData = unknown> = {\n action: TAction | typeof WILDCARD;\n effect: 'allow' | 'deny';\n priority?: number;\n resource: string | typeof WILDCARD;\n role: string | readonly string[];\n when?: WardPredicate<TData>;\n};\n\nexport type NormalizedWardRule<TAction extends string = string, TData = unknown> = Readonly<{\n action: TAction | typeof WILDCARD;\n effect: 'allow' | 'deny';\n priority: number;\n resource: string | typeof WILDCARD;\n role: readonly string[];\n when?: WardPredicate<TData>;\n}>;\n\nexport type WardDecision<TAction extends string = string, TData = unknown> =\n | { allowed: true; rule: Readonly<NormalizedWardRule<TAction, TData>> }\n | { allowed: false; reason: 'explicit-deny'; rule: Readonly<NormalizedWardRule<TAction, TData>> }\n | { allowed: false; reason: 'no-matching-rule' };\n\nexport type WardCheck<TAction extends string = string, TData = unknown> = {\n action: TAction;\n data?: TData;\n resource: string;\n};\n\nexport type WardDecisionResult<TAction extends string = string, TData = unknown> = WardDecision<TAction, TData> & {\n action: TAction;\n resource: string;\n};\n\nexport type WardDecisionInput<TAction extends string = string, TData = unknown> = {\n action: TAction;\n data?: TData;\n principal: Principal;\n resource: string;\n};\n\nexport type WardAllowedActionsInput<TAction extends string = string, TData = unknown> = {\n data?: TData;\n knownActions: readonly TAction[];\n principal: Principal;\n resource: string;\n};\n\nexport type WardRulesInScopeInput<TData = unknown> = {\n data?: TData;\n principal: Principal;\n resource: string;\n};\n\nexport type BoundWardDecisionInput<TAction extends string = string, TData = unknown> = {\n action: TAction;\n data?: TData;\n resource: string;\n};\n\nexport type BoundWardAllowedActionsInput<TAction extends string = string, TData = unknown> = {\n data?: TData;\n knownActions: readonly TAction[];\n resource: string;\n};\n\nexport type BoundWardRulesInScopeInput<TData = unknown> = {\n data?: TData;\n resource: string;\n};\n\nexport type ConflictKind = 'duplicate' | 'shadowed';\n\nexport type WardConflict<TAction extends string = string, TData = unknown> =\n | {\n indexA: number;\n indexB: number;\n kind: 'duplicate';\n ruleA: Readonly<NormalizedWardRule<TAction, TData>>;\n ruleB: Readonly<NormalizedWardRule<TAction, TData>>;\n }\n | {\n kind: 'shadowed';\n shadowedIndex: number;\n shadowedRule: Readonly<NormalizedWardRule<TAction, TData>>;\n shadowingIndex: number;\n shadowingRule: Readonly<NormalizedWardRule<TAction, TData>>;\n };\n\nexport type WardTraceCandidate<TAction extends string = string, TData = unknown> = {\n index: number;\n priority: number;\n rule: Readonly<NormalizedWardRule<TAction, TData>>;\n score: number;\n won: boolean;\n};\n\nexport type WardTrace<TAction extends string = string, TData = unknown> = {\n candidates: WardTraceCandidate<TAction, TData>[];\n decision: WardDecision<TAction, TData>;\n};\n\nexport type Ward<TAction extends string = string, TData = unknown> = {\n allowedActions(input: WardAllowedActionsInput<TAction, TData>): TAction[];\n checkAll(principal: Principal, checks: readonly WardCheck<TAction, TData>[]): WardDecisionResult<TAction, TData>[];\n detectConflicts(): readonly WardConflict<TAction, TData>[];\n explain(input: WardDecisionInput<TAction, TData>): WardDecision<TAction, TData>;\n forUser(principal: UserPrincipal): BoundWard<TAction, TData>;\n rulesInScope(input: WardRulesInScopeInput<TData>): ReadonlyArray<Readonly<NormalizedWardRule<TAction, TData>>>;\n tap(handler: (event: WardEvent<TAction, TData>) => void, options?: { signal?: AbortSignal }): () => void;\n trace(input: WardDecisionInput<TAction, TData>): WardTrace<TAction, TData>;\n};\n\nexport type BoundWard<TAction extends string = string, TData = unknown> = {\n allowedActions(input: BoundWardAllowedActionsInput<TAction, TData>): TAction[];\n checkAll(checks: readonly WardCheck<TAction, TData>[]): WardDecisionResult<TAction, TData>[];\n explain(input: BoundWardDecisionInput<TAction, TData>): WardDecision<TAction, TData>;\n rulesInScope(input: BoundWardRulesInScopeInput<TData>): ReadonlyArray<Readonly<NormalizedWardRule<TAction, TData>>>;\n trace(input: BoundWardDecisionInput<TAction, TData>): WardTrace<TAction, TData>;\n};\n\nexport type WardEvent<TAction extends string = string, TData = unknown> = {\n type: 'decision';\n decision: WardDecision<TAction, TData>;\n action: TAction;\n data?: TData;\n principal: Principal;\n resource: string;\n};\n\nexport type WardOptions<TAction extends string = string, TData = unknown> = {\n maxConflicts?: number;\n onConflict?: (conflict: WardConflict<TAction, TData>) => void;\n strict?: boolean;\n};\n```\n\n`WardDecision`, `WardDecisionResult`, `WardTrace`, `WardTraceCandidate`, and `WardConflict` reference `NormalizedWardRule` (always-array `role`, always-number `priority`).\n\n`Ward`, `BoundWard`, `WardDecision`, `WardDecisionResult`, `WardTrace`, `WardTraceCandidate`, `WardConflict`,\n`NormalizedWardRule`, `WardOptions`, `WardCheck`, `WardAllowedActionsInput`, `WardRulesInScopeInput`, `RuleContext`,\n`WardEvent`, `WardPredicate`, and `ConflictKind` are exported from the root entry point.\n\n## Errors\n\n- `WardError` is the base error class; use `instanceof WardError` for narrowing.\n- `WardConfigError` reports malformed rules, invalid `createWard` options (`onConflict`, `maxConflicts`), invalid principals, and strict conflict initialization.\n- `WardPredicateError` reports a throwing synchronous predicate and includes its `ruleIndex` and cause.\n",
|
|
6
|
-
"usage": "---\ntitle: Ward — Usage Guide\ndescription: Build deterministic authorization policies with immutable rule sets, wildcard support, and runtime predicates.\n---\n\n[[toc]]\n\n## Basic Usage\n\n```ts\nimport { WILDCARD, allow, createWard, deny } from '@vielzeug/ward';\n\nconst ward = createWard([\n allow('viewer', 'posts', ['read']),\n allow('editor', 'posts', ['update']),\n deny('blocked', 'posts', [WILDCARD], { priority: 100 }),\n]);\n```\n\n`allow()`, `deny()`, and `ruleFor()` return `WardRule[]` (one rule per action). Pass them directly to `createWard` — no spread needed. Rules are immutable after creation. Create a new ward to update policy.\n\n## Explain a Decision\n\n```ts\nconst decision = ward.explain({\n principal: { id: 'u1', roles: ['editor'] },\n resource: 'posts',\n action: 'update',\n data: { authorId: 'u1' },\n});\n\nif (decision.allowed) {\n console.log(decision.rule);\n} else {\n console.log(decision.reason); // 'no-matching-rule' | 'explicit-deny'\n}\n```\n\n## Batch Decisions\n\n```ts\nconst results = ward.checkAll({ id: 'u1', roles: ['editor'] }, [\n { resource: 'posts', action: 'read' },\n { resource: 'posts', action: 'update', data: { authorId: 'u1' } },\n]);\n```\n\n## Bound Ward (`forUser`)\n\n```ts\nconst bound = ward.forUser({ id: 'u1', roles: ['editor'] });\n\nbound.explain({ resource: 'posts', action: 'read' });\nbound.trace({ resource: 'posts', action: 'update', data: { authorId: 'u1' } });\nbound.rulesInScope({ resource: 'posts' });\nbound.allowedActions({ resource: 'posts', knownActions: ['read', 'update', 'delete'] as const });\n```\n\n`forUser()` snapshots the principal. Re-bind when roles/identity change.\n\n## Allowed Actions\n\n`allowedActions()` evaluates a provided action set:\n\n```ts\nconst actions = ward.allowedActions({\n principal: { id: 'u1', roles: ['admin'] },\n resource: 'posts',\n knownActions: ['read', 'update', 'delete'] as const,\n});\n```\n\nIt does not fire a `decision` event.\n\n## Rule Introspection\n\n```ts\nconst scoped = ward.rulesInScope({\n principal: { id: 'u1', roles: ['editor'] },\n resource: 'posts',\n});\n```\n\nUse optional `data` to filter predicate-gated matches.\n\n## Trace Candidates\n\n```ts\nconst trace = ward.trace({\n principal: { id: 'u1', roles: ['editor', 'blocked'] },\n resource: 'posts',\n action: 'read',\n});\n\ntrace.candidates.forEach((c) => {\n console.log(c.index, c.priority, c.score, c.won);\n});\n```\n\n`trace()` does not fire a `decision` event.\n\n## Observing Decisions\n\n`tap()` subscribes a handler to ward events. Each `explain()` and `checkAll()` decision fires a `decision` event; `trace()` and `allowedActions()` do not.\n\n```ts\nconst ward = createWard(rules);\nward.tap((event) => console.debug(`ward:${event.type}`, event.decision));\n```\n\nPass an `AbortSignal` to unsubscribe automatically, or call the returned function to unsubscribe manually:\n\n```ts\nconst controller = new AbortController();\nconst unsubscribe = ward.tap((event) => console.debug(event), { signal: controller.signal });\n\n// later\nunsubscribe(); // or controller.abort();\n```\n\nFor structured logging, forward events to a `@vielzeug/rune` logger:\n\n```ts\nimport { createLogger } from '@vielzeug/rune';\nconst log = createLogger({ name: 'ward' });\nward.tap((event) => log.debug(event, 'ward:decision'));\n```\n\n## Predicate Helpers\n\n```ts\nimport { owns, predicate } from '@vielzeug/ward';\n\nconst isOwner = owns('authorId');\nconst canEdit = predicate.and(isOwner, ({ principal }) => principal.id !== '');\n```\n\nAsync predicates are rejected at runtime with `WardPredicateError`.\n\n## Request Guards\n\nUse `explain()` directly at request boundaries. Extract the principal from your framework's request object and pass it to Ward:\n\n```ts\nconst principal = await extractPrincipal(req);\nconst decision = ward.explain({ principal, resource: 'posts', action: 'read' });\n\nif (!decision.allowed) {\n return res.status(403).json({ error: decision.reason });\n}\n```\n\n## Testing\n\nTest policy outcomes through `explain()` so each test captures an allowed, explicit-deny, or no-match result.\n\n```ts\nimport { expect, it } from 'vitest';\n\nit('denies an action with no matching rule', () => {\n expect(\n ward.explain({ principal: { id: 'u1', roles: ['viewer'] }, resource: 'posts', action: 'delete' }).allowed,\n ).toBe(false);\n});\n```\n\n## Framework Integration\n\nKeep Ward independent from rendering frameworks. Obtain a current principal from framework state, bind it with `forUser()`, and rebind whenever identity or roles change.\n\n::: code-group\n\n```tsx [React]\nconst actions = ward.forUser(user).allowedActions({ resource: 'posts', knownActions: ['read', 'update'] as const });\n```\n\n```vue [Vue 3]\n<script setup lang=\"ts\">\nconst actions = ward\n .forUser(user.value)\n .allowedActions({ resource: 'posts', knownActions: ['read', 'update'] as const });\n</script>\n```\n\n```ts [Svelte]\nconst actions = ward.forUser(user).allowedActions({ resource: 'posts', knownActions: ['read', 'update'] as const });\n```\n\n:::\n\n## Working with Other Vielzeug Libraries\n\n### With Wayfinder\n\nEnforce Ward decisions in Wayfinder route guards by calling `explain()` inside the guard callback:\n\n```ts\nconst decision = ward.explain({ principal, resource: route.meta.resource, action: 'read' });\n\nif (!decision.allowed) return '/forbidden';\n```\n\n### With Conduit\n\nInject a Ward instance into Conduit-managed services so authorization checks share a single compiled policy:\n\n```ts\nconst ward = createWard(rules);\ncontainer.register('ward', ward);\n```\n\n## Best Practices\n\n- Model default-deny by adding only explicit allow rules.\n- Keep predicates synchronous and provide required resource data.\n- Assign priority deliberately before relying on specificity.\n- Rebind `forUser()` when identity or roles change.\n- Use `trace()` and `detectConflicts()` to diagnose policy behavior.\n- Enforce authorization again at request and mutation boundaries.\n",
|
|
7
|
-
"examples": "---\ntitle: Ward — Examples\ndescription: Practical examples and recipes for ward.\n---\n\n## Examples\n\n- [Blog Roles](./examples/blog-roles.md)\n- [Multi-Role Rules](./examples/multi-role-rules.md)\n- [Wildcard Action](./examples/wildcard-action.md)\n- [Priority and Overrides](./examples/inheritance-and-overrides.md)\n- [Bound Guard in UI Layer](./examples/bound-guard-in-ui-layer.md)\n- [Rule Specificity](./examples/disabling-wildcard-fallback.md)\n- [Auditing Decisions](./examples/logger-for-auditing.md)\n- [Fresh Ward Per Test](./examples/snapshot-restore-for-test-isolation.md)\n- [Conflict Detection](./examples/conflict-detection.md)\n- [Trace a Decision](./examples/trace-decision.md)\n"
|
|
8
|
-
},
|
|
9
|
-
"examples": [
|
|
10
|
-
{
|
|
11
|
-
"id": "basic-rules",
|
|
12
|
-
"code": "import { ANONYMOUS, WILDCARD, allow, createWard, deny } from '@vielzeug/ward'\n\n// Role-based access control with wildcard and anonymous support\nconst ward = createWard([\n allow(WILDCARD, 'posts', ['read']),\n allow('editor', 'posts', ['update']),\n deny('blocked', WILDCARD, [WILDCARD]),\n allow(ANONYMOUS, 'posts', ['read']),\n])\n\nconst viewer = { id: 'u1', roles: ['viewer'] }\nconst editor = { id: 'u2', roles: ['editor'] }\nconst blocked = { id: 'u3', roles: ['blocked'] }\n\nconst explain = (p: typeof viewer | null, action: string) =>\n ward.explain({ action, principal: p, resource: 'posts' }).allowed\n\nconsole.log('viewer read: ', explain(viewer, 'read')) // true\nconsole.log('viewer update:', explain(viewer, 'update')) // false\nconsole.log('editor update:', explain(editor, 'update')) // true\nconsole.log('blocked read: ', explain(blocked, 'read')) // false\nconsole.log('anon read: ', explain(null, 'read')) // true",
|
|
13
|
-
"name": "Basic Rules"
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"id": "basic-setup",
|
|
17
|
-
"code": "import { ANONYMOUS, allow, createWard } from '@vielzeug/ward'\n\n// role accepts a string or an array of strings (OR semantics)\nconst ward = createWard([\n allow(['viewer', 'editor', 'admin'], 'posts', ['read']),\n allow(['editor', 'admin'], 'posts', ['update']),\n allow('admin', 'posts', ['delete']),\n allow(ANONYMOUS, 'posts', ['read']),\n])\n\nconst viewer = { id: '1', roles: ['viewer'] }\nconst editor = { id: '2', roles: ['editor'] }\nconst admin = { id: '3', roles: ['admin'] }\n\nconst can = (p: typeof viewer | null, action: string) =>\n ward.explain({ action, principal: p, resource: 'posts' }).allowed\n\nconsole.log('Viewer can read:', can(viewer, 'read')) // true\nconsole.log('Viewer can update:', can(viewer, 'update')) // false\nconsole.log('Editor can update:', can(editor, 'update')) // true\nconsole.log('Admin can delete:', can(admin, 'delete')) // true\nconsole.log('Anonymous can read:', can(null, 'read')) // true",
|
|
18
|
-
"name": "Basic Setup — Multi-Role Rules"
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"id": "batch-decisions",
|
|
22
|
-
"code": "import { allow, createWard, deny } from '@vielzeug/ward'\n\n// checkAll returns WardDecisionResult[] — each entry carries resource + action\nconst ward = createWard([\n allow('editor', 'posts', ['read', 'update']),\n deny('editor', 'posts', ['delete']),\n])\n\nconst editor = { id: 'u1', roles: ['editor'] }\n\nconst results = ward.checkAll(editor, [\n { resource: 'posts', action: 'read' },\n { resource: 'posts', action: 'update' },\n { resource: 'posts', action: 'delete' },\n { resource: 'comments', action: 'read' },\n])\n\nfor (const r of results) {\n const status = r.allowed ? '✅ allow' : `❌ ${r.reason}`\n console.log(`${r.resource}:${r.action.padEnd(8)} ${status}`)\n}",
|
|
23
|
-
"name": "Batch Decisions"
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"id": "bound-view",
|
|
27
|
-
"code": "import { allow, createWard, deny, predicate } from '@vielzeug/ward'\n\n// Principal-bound view: capture user once, check many times\nconst ward = createWard([\n allow('editor', 'posts', ['read', 'update']),\n // delete: allow only when user owns the post (higher priority wins)\n allow('editor', 'posts', ['delete'], { when: predicate.owns('authorId'), priority: 1 }),\n deny('editor', 'posts', ['delete'], { priority: 0 }),\n])\n\nconst user = ward.forUser({ id: 'alice', roles: ['editor'] })\n\nconsole.log('read: ', user.explain({ action: 'read', resource: 'posts' }).allowed)\nconsole.log('update: ', user.explain({ action: 'update', resource: 'posts' }).allowed)\n\n// delete requires ownership\nconst myPost = { authorId: 'alice' }\nconst otherPost = { authorId: 'bob' }\nconsole.log('delete own: ', user.explain({ action: 'delete', data: myPost, resource: 'posts' }).allowed)\nconsole.log('delete other: ', user.explain({ action: 'delete', data: otherPost, resource: 'posts' }).allowed)\n\n// allowedActions — enumerate what alice can do\nconst actions = user.allowedActions({ data: myPost, knownActions: ['read', 'update', 'delete'], resource: 'posts' })\nconsole.log('allowed: ', actions)",
|
|
28
|
-
"name": "Bound View"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"id": "conflict-detection",
|
|
32
|
-
"code": "// Detect rule conflicts — duplicate and shadowed rules — at startup\nimport { createWard } from '@vielzeug/ward'\n\nconst ward = createWard(\n [\n // Rule 0: viewer can read posts\n { role: 'viewer', resource: 'posts', action: 'read', effect: 'allow' },\n // Rule 1: duplicate — same (role, resource, action), different effect.\n // One of these can never fire.\n { role: 'viewer', resource: 'posts', action: 'read', effect: 'deny' },\n // Rule 2+3: shadowed — the wildcard-action allow at higher priority\n // will always win over this specific deny.\n { role: 'admin', resource: 'posts', action: '*', effect: 'allow', priority: 10 },\n { role: 'admin', resource: 'posts', action: 'delete', effect: 'deny', priority: 5 },\n ],\n {\n onConflict: (c) => {\n if (c.kind === 'duplicate') {\n console.log(`[conflict] duplicate: Rule[${c.indexA}] always wins over Rule[${c.indexB}]`)\n } else {\n console.log(`[conflict] shadowed: Rule[${c.shadowedIndex}] always overridden by Rule[${c.shadowingIndex}]`)\n }\n },\n },\n)\n\nconst conflicts = ward.detectConflicts()\nconsole.log('Total conflicts detected:', conflicts.length)\n\nconflicts.forEach((c) => {\n if (c.kind === 'duplicate') {\n console.log(` - duplicate: Rule[${c.indexA}] (${c.ruleA.effect}) vs Rule[${c.indexB}] (${c.ruleB.effect})`)\n } else {\n console.log(` - shadowed: Rule[${c.shadowedIndex}] (${c.shadowedRule.effect}) by Rule[${c.shadowingIndex}] (${c.shadowingRule.effect})`)\n }\n})",
|
|
33
|
-
"name": "Conflict Detection"
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
"id": "dynamic-permissions",
|
|
37
|
-
"code": "import { allow, createWard, predicate } from '@vielzeug/ward'\n\nconst ward = createWard([\n allow('user', 'posts', ['update'], { when: predicate.owns('authorId') }),\n])\n\nconst user1 = { id: 'user1', roles: ['user'] }\nconst user2 = { id: 'user2', roles: ['user'] }\nconst post = { id: 'post1', authorId: 'user1', title: 'My Post' }\n\nconsole.log('Author can update: ', ward.explain({ action: 'update', data: post, principal: user1, resource: 'posts' }).allowed)\nconsole.log('Non-author can update: ', ward.explain({ action: 'update', data: post, principal: user2, resource: 'posts' }).allowed)",
|
|
38
|
-
"name": "Dynamic Permissions — Ownership Rules"
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
"id": "multi-role-rules",
|
|
42
|
-
"code": "import { ANONYMOUS, createWard } from '@vielzeug/ward'\n\n// A single rule can cover multiple roles with array syntax.\n// Semantics are OR: the principal must hold at least one of the listed roles.\nconst ward = createWard([\n // Everyone (including anonymous) can read public content\n { role: [ANONYMOUS, 'user', 'moderator', 'admin'], resource: 'articles', action: 'read', effect: 'allow' },\n // Registered users and above can comment\n { role: ['user', 'moderator', 'admin'], resource: 'articles', action: 'comment', effect: 'allow' },\n // Moderators and admins can remove content\n { role: ['moderator', 'admin'], resource: 'articles', action: 'delete', effect: 'allow' },\n // Only admins can pin articles\n { role: 'admin', resource: 'articles', action: 'pin', effect: 'allow' },\n])\n\nconst guest = null\nconst user = { id: '1', roles: ['user'] }\nconst moderator = { id: '2', roles: ['moderator'] }\nconst admin = { id: '3', roles: ['admin'] }\n\nconst ACTIONS = ['read', 'comment', 'delete', 'pin'] as const\n\nfor (const [label, principal] of [['guest', guest], ['user', user], ['moderator', moderator], ['admin', admin]] as const) {\n const allowed = ward.allowedActions({ knownActions: ACTIONS, principal, resource: 'articles' })\n console.log(`${label} can:`, allowed)\n}",
|
|
43
|
-
"name": "Multi-Role Rules"
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
"id": "permission-checks",
|
|
47
|
-
"code": "import { allow, createWard, deny } from '@vielzeug/ward'\n\nconst ward = createWard([\n allow('editor', 'articles', ['read', 'create', 'update']),\n deny('editor', 'articles', ['delete']),\n allow('viewer', 'articles', ['read']),\n])\n\nconst editor = { id: '1', roles: ['editor'] }\nconst viewer = { id: '2', roles: ['viewer'] }\n\nconsole.log('Editor can read: ', ward.explain({ action: 'read', principal: editor, resource: 'articles' }).allowed)\nconsole.log('Editor can delete: ', ward.explain({ action: 'delete', principal: editor, resource: 'articles' }).allowed)\nconsole.log('Viewer can create: ', ward.explain({ action: 'create', principal: viewer, resource: 'articles' }).allowed)\n\n// Full decision object with deny reason\nconst decision = ward.explain({ action: 'delete', principal: editor, resource: 'articles' })\nif (!decision.allowed) console.log('Deny reason:', decision.reason)",
|
|
48
|
-
"name": "Permission Checks"
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"id": "permission-management",
|
|
52
|
-
"code": "import { createWard } from '@vielzeug/ward'\n\nconst ward = createWard([\n { role: 'user', resource: 'comments', action: 'read', effect: 'allow' },\n { role: 'moderator', resource: 'comments', action: 'delete', effect: 'allow' },\n { role: 'banned', resource: 'comments', action: 'delete', effect: 'deny', priority: 100 },\n])\n\nconst moderator = { id: 'm1', roles: ['moderator'] }\nconst bannedModerator = { id: 'm2', roles: ['moderator', 'banned'] }\n\nconsole.log('Rules in scope for moderator:', ward.rulesInScope({ principal: moderator, resource: 'comments' }))\nconsole.log('Single decision:', ward.explain({ action: 'delete', principal: bannedModerator, resource: 'comments' }))\nconsole.log('Batch decisions:', ward.checkAll(bannedModerator, [\n { resource: 'comments', action: 'read' },\n { resource: 'comments', action: 'delete' },\n]))",
|
|
53
|
-
"name": "Introspection and Batch Decisions"
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
"id": "role-hierarchy",
|
|
57
|
-
"code": "import { allow, createWard } from '@vielzeug/ward'\n\nconst ward = createWard([\n allow('editor', 'posts', ['read']),\n allow('moderator', 'posts', ['delete']),\n])\n\nconst user = { id: '42', roles: ['editor', 'moderator'] }\nconst bound = ward.forUser(user)\n\nconsole.log('Can read posts: ', bound.explain({ action: 'read', resource: 'posts' }).allowed)\nconsole.log('Can delete posts: ', bound.explain({ action: 'delete', resource: 'posts' }).allowed)\nconsole.log('Allowed actions: ', bound.allowedActions({ knownActions: ['read', 'delete', 'update'], resource: 'posts' }))",
|
|
58
|
-
"name": "Bound Multi-Role Access"
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
"id": "rule-factories",
|
|
62
|
-
"code": "import { allow, createWard, deny, predicate } from '@vielzeug/ward'\n\n// Rule factories with ownership predicate\nconst ward = createWard([\n allow('viewer', 'posts', ['read']),\n allow('editor', 'posts', ['read', 'update']),\n // Ownership predicate — update only your own posts\n allow('editor', 'posts', ['update'], { when: predicate.owns('authorId') }),\n deny('blocked', 'posts', ['read', 'update']),\n])\n\nconst editor = { id: 'u1', roles: ['editor'] }\n\n// read: allowed (no predicate required)\nconsole.log('read: ', ward.explain({ action: 'read', principal: editor, resource: 'posts' }).allowed)\n\n// update with own post\nconst myPost = { authorId: 'u1' }\nconsole.log('update own: ', ward.explain({ action: 'update', data: myPost, principal: editor, resource: 'posts' }).allowed)\n\n// update someone else's post\nconst otherPost = { authorId: 'u2' }\nconsole.log('update other:', ward.explain({ action: 'update', data: otherPost, principal: editor, resource: 'posts' }).allowed)",
|
|
63
|
-
"name": "Rule Factories & Predicates"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
"id": "trace-decision",
|
|
67
|
-
"code": "// Inspect all matching rule candidates and why a particular rule won\nimport { WILDCARD, createWard } from '@vielzeug/ward'\n\nconst ward = createWard([\n { role: WILDCARD, resource: 'posts', action: 'read', effect: 'allow', priority: 0 },\n { role: 'editor', resource: 'posts', action: 'read', effect: 'allow', priority: 0 },\n { role: 'blocked', resource: 'posts', action: 'read', effect: 'deny', priority: 5 },\n])\n\nconst { decision, candidates } = ward.trace({\n action: 'read',\n principal: { id: 'u1', roles: ['editor', 'blocked'] },\n resource: 'posts',\n})\n\ncandidates.forEach(({ index, rule, priority, score, won }) => {\n console.log(\n won ? '[WINNER]' : '[ ]',\n `Rule[${index}]`,\n `effect=${rule.effect}`,\n `role=${rule.role}`,\n `priority=${priority}`,\n `score=${score}`,\n )\n})\n\nconsole.log('Decision:', decision.allowed ? 'allow' : `deny (${decision.reason})`)",
|
|
68
|
-
"name": "Trace — Inspect Matching Candidates"
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
"id": "wildcard-permissions",
|
|
72
|
-
"code": "import { WILDCARD, allow, createWard } from '@vielzeug/ward'\n\nconst ward = createWard([\n allow('admin', WILDCARD, [WILDCARD]),\n allow('user', 'posts', ['read']),\n])\n\nconst admin = { id: '1', roles: ['admin'] }\nconst user = { id: '2', roles: ['user'] }\n\nconst can = (p: typeof admin, resource: string, action: string) =>\n ward.explain({ action, principal: p, resource }).allowed\n\nconsole.log('Admin can delete users:', can(admin, 'users', 'delete'))\nconsole.log('User can read posts:', can(user, 'posts', 'read'))\nconsole.log('User can delete posts:', can(user, 'posts', 'delete'))\nconsole.log('Known actions for admin:', ward.allowedActions({ knownActions: ['read', 'delete', 'archive'], principal: admin, resource: 'users' }))",
|
|
73
|
-
"name": "Wildcard Rules"
|
|
74
|
-
}
|
|
75
|
-
],
|
|
76
|
-
"typeSignatures": {
|
|
77
|
-
"allow": "export { allow, deny, owns, predicate, ruleFor } from './builder';",
|
|
78
|
-
"deny": "export { allow, deny, owns, predicate, ruleFor } from './builder';",
|
|
79
|
-
"owns": "export { allow, deny, owns, predicate, ruleFor } from './builder';",
|
|
80
|
-
"predicate": "export { allow, deny, owns, predicate, ruleFor } from './builder';",
|
|
81
|
-
"ruleFor": "export { allow, deny, owns, predicate, ruleFor } from './builder';",
|
|
82
|
-
"ANONYMOUS": "export { ANONYMOUS, WILDCARD } from './constants';",
|
|
83
|
-
"WILDCARD": "export { ANONYMOUS, WILDCARD } from './constants';",
|
|
84
|
-
"WardConfigError": "export { WardConfigError, WardError, WardPredicateError } from './errors';",
|
|
85
|
-
"WardError": "export { WardConfigError, WardError, WardPredicateError } from './errors';",
|
|
86
|
-
"WardPredicateError": "export { WardConfigError, WardError, WardPredicateError } from './errors';",
|
|
87
|
-
"createWard": "export { createWard } from './factory';",
|
|
88
|
-
"matchesPattern": "export { matchesPattern, patternCovers } from './resource';",
|
|
89
|
-
"patternCovers": "export { matchesPattern, patternCovers } from './resource';",
|
|
90
|
-
"BoundWard": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
91
|
-
"BoundWardAllowedActionsInput": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
92
|
-
"BoundWardDecisionInput": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
93
|
-
"BoundWardRulesInScopeInput": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
94
|
-
"ConflictKind": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
95
|
-
"NormalizedWardRule": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
96
|
-
"Principal": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
97
|
-
"RuleContext": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
98
|
-
"UserPrincipal": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
99
|
-
"Ward": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
100
|
-
"WardAllowedActionsInput": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
101
|
-
"WardCheck": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
102
|
-
"WardConflict": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
103
|
-
"WardDecision": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
104
|
-
"WardDecisionInput": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
105
|
-
"WardDecisionResult": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
106
|
-
"WardEvent": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
107
|
-
"WardOptions": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
108
|
-
"WardPredicate": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
109
|
-
"WardRule": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
110
|
-
"WardRulesInScopeInput": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
111
|
-
"WardTrace": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';",
|
|
112
|
-
"WardTraceCandidate": "export type {\n BoundWard,\n BoundWardAllowedActionsInput,\n BoundWardDecisionInput,\n BoundWardRulesInScopeInput,\n ConflictKind,\n NormalizedWardRule,\n Principal,\n RuleContext,\n UserPrincipal,\n Ward,\n WardAllowedActionsInput,\n WardCheck,\n WardConflict,\n WardDecision,\n WardDecisionInput,\n WardDecisionResult,\n WardEvent,\n WardOptions,\n WardPredicate,\n WardRule,\n WardRulesInScopeInput,\n WardTrace,\n WardTraceCandidate,\n} from './types';"
|
|
113
|
-
}
|
|
114
|
-
}
|