@gomagentic/verdict-engine
v0.1.1
Published
Verdict embedded evaluator: VIR interpreter, decision combining, tracing, caches. Zero network calls; runs on Workers, Lambda, Bun, Deno, Node.
Maintainers
Readme
@gomagentic/verdict-engine
The embedded evaluator: microsecond authorization decisions, zero network calls.
Part of Verdict — a serverless-first authorization engine. Policies (RBAC / ABAC / ReBAC) compile once and decide in microseconds, embedded in your app, behind a central PDP, or synced to the edge.
Install
npm install @gomagentic/verdict-engineThe engine evaluates a compiled bundle; it does not author one. Compile your policy source to a bundle with @gomagentic/verdict-dsl, or receive a signed bundle from a control plane and load it with Verdict.fromBundle.
Quick start
import { allows } from "@gomagentic/verdict-core";
import { Verdict } from "@gomagentic/verdict-engine";
const verdict = await Verdict.fromBundle(bundle); // verifies content hash; or Verdict.fromProgram(vir)
const decision = verdict.check({
principal: { id: "u_42", roles: ["employee"], attr: { department: "eng", level: 4 } },
resource: { kind: "leave", id: "lv_9", attr: { managerId: "u_42", department: "eng" } },
actions: ["approve"],
});
allows(decision, "approve"); // true | false — default deny, alwayscheck() returns a Decision: results maps each action to its ActionEffect (Allow / Deny plus a reason), and meta carries requestId, bundleHash, bundleVersion, latencyUs, cacheHit, and evaluatedAt. Read a single verdict with allows(decision, action) from @gomagentic/verdict-core, or use the engine's own verdict.allows(request) for a single-action boolean check. batchCheck() evaluates many (principal, resource, actions) entries under one shared context.
explain() is check() with the full trace forced on. The returned Decision gains a trace: the rules the evaluator visited (matched policy and rule, evaluated conditions), the sorted missingAttributes that pushed conditions to UNKNOWN, and the derivedRoles computed for the request — produced by the evaluator itself, not reconstructed afterward.
const explained = verdict.explain({ principal, resource, actions: ["approve"] });
explained.trace?.missingAttributes; // e.g. ["resource.attr.ownerId"]Decisions are pure functions of (bundle, principal, resource, actions, context) — the same bundle yields byte-identical decisions on Cloudflare Workers, Lambda, Deno, Bun, and Node, with no network calls. A warm check() runs in ~12 µs mean / 29 µs p99; a 1000-entry batch in ~9.6 ms; loading a 100-policy bundle in ~30 µs.
Key exports
| Export | Description |
|---|---|
| Verdict | The engine. fromBundle / fromProgram to load; check, explain, batchCheck, allows to decide. |
| VerdictOptions | Construction options: extern function impls, decisionCache, tenantId, relationships resolver. |
| DecisionCache / DecisionCacheOptions | Opt-in per-process LRU keyed on the full canonical (principal, resource, action); maxEntries, ttlMs. |
| MemoryRelationshipResolver / RelationshipResolver | ReBAC seam for related(); supply tuples the resolver answers synchronously (PIP-prefetch pattern). |
| ExternFunction | Synchronous host function backing an extern declaration; fetch async attributes before evaluation, not inside it. |
| EVAL_LIMITS / BudgetExceeded | Per-check instruction budget and quantifier caps; exhausting the budget fails the whole check closed (all-actions DENY). |
| LoadedProgram | A VirProgram prepared for evaluation — patterns compiled, policies indexed and pre-sorted at load time. |
Lower-level building blocks are also exported for tooling and conformance work: applicablePolicies, createRequestEnv, decideAction, evalCondition, and the value primitives (UNKNOWN, VDuration, VTimestamp, deepEqual, compareValues, kleeneAnd / kleeneOr / kleeneNot, parseDuration, parseTimestamp).
Documentation
License
Apache-2.0
