AnterisLab

API reference

The complete public surface of @anterislab/guard. All symbols below are exported from the package root unless marked otherwise.

Guard class

new Guard(options: GuardOptions)

Creates a guard. The constructor validates the configuration and throws GuardConfigError for anything that would weaken the guarantees.

See configuration.md for every option.

guard.wrap<T>(target: T, options: WrapOptions): T

Wraps an object so that every method goes through the gate before executing. Methods listed in passthrough are exempt.

Returns a Proxy over target. The original object is not modified.

const safe = guard.wrap(agent, { agent: 'billing-bot', passthrough: ['describe'] });
await safe.charge(10);       // evaluated
safe.describe();             // passthrough

Throws: any GuardError from the underlying decide() call.

guard.wrapFn<A, R>(fn, options: WrapFnOptions<A>): (...args: A) => Promise<R>

Wraps a single function. The action is derived from the arguments by the toAction mapper.

const charge = guard.wrapFn(agent.charge, {
  agent: 'billing-bot',
  toAction: (amount) => ({ type: 'payment', amount, currency: 'EUR' }),
});
await charge(4200);

Throws: any GuardError from the underlying decide() call.

guard.decide(action, agent): Promise<ParsedDecision>

Evaluates an action and decides. This is the only place where a decision is made. wrap and wrapFn both call it.

Returns the decision when the action may proceed; throws otherwise.

Use this directly if you need fine-grained control over the action descriptor and don't want to wrap a function.

const decision = await guard.decide(
  { type: 'payment', amount: 100, currency: 'EUR' },
  'billing-bot',
);
console.log(decision.decision);   // 'APPROVED' | 'FLAGGED'

guard.halt(reason, evidence?): Promise<KillSwitchStatus>

Engages the kill switch locally, right now, with no network round-trip. Requires killSwitch to be configured; otherwise throws GuardConfigError.

See kill-switch.md.

guard.resume(options): Promise<KillSwitchStatus>

Clears a local halt. Requires a verified control-plane state newer than the halt, or breakGlass: true with an explicit reason.

await guard.resume({ reason: 'incident resolved', evidence: 'INC-1234' });

guard.status(): Promise<KillSwitchStatus>

Returns the current kill-switch status (verified). Refreshes if the cached state is stale.

guard.startStream(): Promise<() => void>

Opens the SSE stream for push propagation of halt/resume events. Returns a stop function.

const stop = await guard.startStream();
// ...
stop();   // closes the stream

Error classes

Every error thrown by the SDK extends GuardError. A single catch block can distinguish between all the cases.

Class code When it is thrown
GuardBlockedError GUARD_BLOCKED The policy denied, or the verdict was unrecognized
GuardPausedError GUARD_PAUSED Verdict is PAUSED; human review required
GuardHaltedError GUARD_HALTED Kill switch is active
GuardQuotaError GUARD_QUOTA_EXCEEDED 402; plan quota exhausted
GuardAuthError GUARD_UNAUTHORIZED (401) / GUARD_FORBIDDEN (403) Invalid key or agent out of scope
GuardPolicyError GUARD_STALE_POLICY 409; stale policy snapshot
GuardUnavailableError GUARD_UNAVAILABLE Guard unreachable (timeout, network, 5xx)
GuardConfigError GUARD_CONFIG Invalid configuration
GuardStateInvalidError GUARD_STATE_INVALID Kill-switch state too stale

See error-handling.md for reactions and examples.

GuardError

Base class. Properties:

GuardBlockedError

GuardQuotaError

GuardUnavailableError

GuardHaltedError

Utility functions

parseVerdict(body, expectedAgent?): VerdictOutcome

Parses an /evaluate response body into a canonical decision. Implements the allow-list: only APPROVED and FLAGGED authorize; everything else is a denial.

Used internally by Guard.decide(). Exported for advanced integrations.

const outcome = parseVerdict({ decision: 'BLOCKED', reason: 'limit' });
if (outcome.ok) {
  console.log(outcome.decision.decision);
}

canonicalizeVerdict(value): CanonicalVerdict | null

Normalizes a raw value to a canonical verdict. Returns null for unrecognized values. Accepts legacy aliases (allow, approved, block, deny, ...) and the canonical names.

canonicalizeVerdict('allow');        // 'APPROVED'
canonicalizeVerdict('YES_PLEASE');   // null

isAuthorizing(verdict): boolean

Returns true only for APPROVED and FLAGGED.

actionDigest(action): string

Computes a SHA-256 digest of the action, with deterministic key ordering. Used internally to fingerprint the arguments of a wrapped function.

Constants

SDK_VERSION

The current version of the SDK. Included in the x-anterislab-sdk header on every request.

import { SDK_VERSION } from '@anterislab/guard';
console.log(SDK_VERSION);   // e.g. '0.2.1'

Types

All types are exported as TypeScript types. They are not runtime values.

GuardOptions

Constructor options for Guard. See configuration.md.

WrapOptions

interface WrapOptions {
  agent: string;
  passthrough?: readonly string[];
}

WrapFnOptions<A>

interface WrapFnOptions<A extends unknown[]> {
  agent: string;
  toAction: (...args: A) => Record<string, unknown>;
}

GuardAction

The shape of the action descriptor sent to /api/v1/evaluate. Only type is required.

interface GuardAction {
  type: string;
  target?: string;
  domain?: string;
  amount?: number;
  currency?: string;
  recipients?: number;
  query?: string;
  direction?: 'inbound' | 'outbound';
  external?: boolean;
  metadata?: Record<string, unknown>;
}

CanonicalVerdict

type CanonicalVerdict = 'APPROVED' | 'FLAGGED' | 'PAUSED' | 'BLOCKED';

ParsedDecision

The result of a successful parseVerdict or decide.

interface ParsedDecision {
  decision: CanonicalVerdict;
  reason: string;
  policy: string | null;
  decisionId: string | null;
  latencyMs: number | null;
  agent: string | null;
}

VerdictOutcome

type VerdictOutcome =
  | { ok: true; decision: ParsedDecision }
  | { ok: false; code: string; detail: string };

Kill switch

The kill switch is documented in depth in kill-switch.md. This section is a quick reference for the exports.

KillSwitchManager

The class behind guard.halt(), guard.resume(), guard.status(), and guard.startStream(). Can be instantiated directly for use outside Guard.

See kill-switch.md.

Kill-switch error classes

Class code
KillSwitchError (base) —
KillSwitchHaltedError KILL_SWITCH_HALTED
KillSwitchUnavailableError KILL_SWITCH_STATE_UNAVAILABLE
KillSwitchStaleError KILL_SWITCH_STATE_STALE
KillSwitchRollbackError KILL_SWITCH_STATE_ROLLBACK
KillSwitchStateInvalidError KILL_SWITCH_STATE_INVALID
KillSwitchLocalHaltError KILL_SWITCH_LOCAL_HALT

Every subclass extends KillSwitchError, which sets failClosed = true.

KillSwitchStatus

interface KillSwitchStatus {
  halted: boolean;
  reason: string;
  epoch: number;
  origin: 'control-plane' | 'local';
  verified: boolean;
  tenant: string;
  agent: string;
  at: number;
  fetchedAt: number | null;
  token?: string;
}

KillSwitchClientEvent

interface KillSwitchClientEvent {
  type: 'state' | 'halted' | 'resumed' | 'refused' | 'error'
      | 'local_halt' | 'local_resume';
  at: number;
  epoch?: number;
  reason: string;
  origin?: 'control-plane' | 'local';
}

Mock module

Imported via the @anterislab/guard/mock subpath. Never included in the main bundle.

See testing.md for usage.

createMockFetch(responder): MockFetch

Creates a mock fetch implementation. Never performs a network call.

import { createMockFetch, approvedVerdict } from '@anterislab/guard/mock';

const mock = createMockFetch({ status: 200, body: approvedVerdict() });
const guard = new Guard({ apiKey: 'test-key', fetchImpl: mock.fetch });

MockFetch

interface MockFetch {
  fetch: typeof fetch;
  calls: MockRequest[];
  readonly evaluateCalls: number;
  reset(): void;
}

MockRoute

interface MockRoute {
  status: number;
  body?: unknown;
  raw?: string;
  headers?: Record<string, string>;
  delayMs?: number;
}

MockRequest

interface MockRequest {
  url: string;
  method: string;
  headers: Record<string, string>;
  body: string | null;
}

MockResponder

type MockResponder =
  | MockRoute
  | readonly MockRoute[]
  | ((request: MockRequest) => MockRoute);

Verdict builders

Each returns a canonical verdict body as a plain object.

signBody(secret, rawBody): string

Computes an HMAC-SHA256 signature over rawBody, formatted as sha256=<hex>, matching what verifyVerdict expects.

const body = JSON.stringify(approvedVerdict());
const signature = signBody(SECRET, body);
const mock = createMockFetch({
  status: 200,
  raw: body,
  headers: { 'x-anterislab-signature': signature },
});