npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@govplane/runtime-sdk

v0.5.0

Published

Govplane Runtime SDK (Node/TS)

Downloads

108

Readme

@govplane/runtime-sdk

Official Govplane Runtime SDK for Node.js.

The Govplane Runtime SDK is a secure, production-grade client and policy engine designed to consume precompiled runtime governance bundles and evaluate decisions locally, with zero PII, no exposed endpoints, and minimal operational risk.

It is intended for backend services, workers, gateways, and critical paths that must react to policy changes in near real-time without delegating decisions to a remote service.


Architecture

┌─────────────────────────────────────────────────────────┐
│                    Your Application                      │
│                                                          │
│  client.evaluate({ target, context })                    │
│         │                                                │
│         ▼                                                │
│  ┌─────────────────┐   bundle cache   ┌───────────────┐ │
│  │  PolicyEngine   │◄─────────────────│ RuntimeClient │ │
│  │  (in-process)   │                  │  (polling)    │ │
│  └────────┬────────┘                  └──────┬────────┘ │
│           │ Decision                         │ HTTP     │
│           ▼                                  ▼          │
│     allow / deny /              Govplane Control Plane   │
│     throttle / kill_switch /    (bundle endpoint only)  │
│     custom                                               │
└─────────────────────────────────────────────────────────┘

| Property | Details | |---|---| | Decision latency | < 1 ms (in-process evaluation) | | Network dependency | Bundle fetch only — evaluation is offline-safe | | PII in traces | None — context is never included in trace events | | Fail-safe | Deny-by-default when bundle is missing or invalid | | Bundle delivery | Server-compiled JSON bundle, not evaluated server-side |


Design Principles

  • No exposed endpoints – no middleware, no inbound surface
  • Local-first evaluation – decisions are made in-process
  • Zero PII by design – strict context validation and heuristic PII key blocking
  • Precompiled policies – no DSL or dynamic code at runtime
  • Deterministic outcomes – same input, same decision
  • Cheap polling – HEAD + ETag + conditional GET
  • Failure-safe – backoff, degraded mode, deny-by-default

Key Capabilities

Runtime Client

  • Efficient HEAD-first polling using ETag and If-None-Match
  • In-memory bundle cache
  • warmStart() to block until first bundle is ready
  • Configurable polling interval
  • Burst mode for incident response
  • Exponential backoff with jitter
  • Automatic degraded state with nextRetryAt reporting
  • Status subscriptions via onStatus() and bundle update subscriptions via onUpdate()

Policy Engine

  • Five effect types: allow, deny, kill_switch, throttle, custom
  • Deny-by-default – no bundle or no match always denies
  • Fixed precedence: kill_switch > deny > throttle > allow > custom > deny-by-default
  • Throttle selects the most restrictive matching rule
  • thenEffect / elseEffect for conditional branching within a single rule
  • Policy-level defaults as a fallback when no rule matches
  • Deterministic rule ordering by priority, then policyKey, then ruleId
  • Precompiled when AST evaluation — no dynamic code execution
  • Optional automatic JSON parsing of custom effect values (parseCustomEffect)

Security & Context Safety

  • Explicit context allowedKeys allowlist — unknown keys throw immediately
  • Heuristic PII key blocking (blockLikelyPiiKeys)
  • Configurable limits: maxStringLen, maxArrayLen
  • Context policy is fully configurable per engine instance
  • Disable validation only in controlled test environments

Decision Tracing

  • evaluate() for plain decisions; evaluateWithTrace() for traced decisions
  • Four trace levels: off, errors, sampled, full
  • Sampling rate and per-window budget controls
  • force: true to bypass sampling for debug sessions
  • Compact or full format (full includes per-rule breakdown)
  • Synchronous and async trace sinks with bounded queues and drop strategies
  • flushTraces() for graceful shutdown

Requirements

  • Node.js ≥ 18
  • A valid Govplane Runtime Key (rk_live_… or rk_test_…)

Installation

npm install @govplane/runtime-sdk
yarn add @govplane/runtime-sdk
# or
pnpm add @govplane/runtime-sdk

Quick Start

import { RuntimeClient } from "@govplane/runtime-sdk";

const client = new RuntimeClient({
  baseUrl:    "https://123456.runtime.govplane.com/",
  runtimeKey: process.env.GP_RUNTIME_KEY!,
});

await client.warmStart();   // block until the first bundle is cached
client.start();             // begin background polling (every 5 s by default)

const result = client.evaluate({
  target:  { service: "payments", resource: "checkout", action: "create" },
  context: { plan: "pro", country: "ES", isAuthenticated: true },
});

console.log(result.decision); // "allow" | "deny" | "throttle" | "kill_switch" | "custom"

Effect Types

The engine returns one of five decision types, applied in this fixed precedence order:

kill_switch  >  deny  >  throttle  >  allow  >  custom  >  deny-by-default

| decision | When it fires | |---------------|---------------| | allow | An allow rule matched, or the policy default is allow. | | deny | A deny rule matched, no rule matched (deny-by-default), or the policy default is deny. | | kill_switch | A kill_switch rule or policy default is active. Always wins. | | throttle | A throttle rule or policy default matched. Most restrictive wins. | | custom | A custom rule or policy default matched — carries an arbitrary string value. |


Decision Shape

evaluate() always returns a Decision object discriminated by decision:

type Decision =
  | { decision: "allow";
      reason: "default" | "rule"; policyKey?: string; ruleId?: string }
  | { decision: "deny";
      reason: "default" | "rule"; policyKey?: string; ruleId?: string }
  | { decision: "kill_switch";
      reason: "default" | "rule"; policyKey?: string; ruleId?: string;
      killSwitch: { service: string; reason?: string } }
  | { decision: "throttle";
      reason: "default" | "rule"; policyKey?: string; ruleId?: string;
      throttle: { limit: number; windowSeconds: number; key: string } }
  | { decision: "custom";
      reason: "default" | "rule"; policyKey?: string; ruleId?: string;
      value: string; parsedValue?: unknown };

Handling every decision type

const result = client.evaluate({ target, context });

if (result.decision === "allow") {
  return next();
}

if (result.decision === "deny") {
  return reply.status(403).send({ error: "Forbidden", policy: result.policyKey });
}

if (result.decision === "throttle") {
  const allowed = await rateLimiter.check(
    result.throttle.key === "tenant" ? ctx.tenantId : ctx.userId,
    result.throttle.limit,
    result.throttle.windowSeconds,
  );
  if (!allowed) return reply.status(429).header("Retry-After", String(result.throttle.windowSeconds)).send();
  return next();
}

if (result.decision === "kill_switch") {
  return reply.status(503).send({ error: "Service Unavailable", reason: result.killSwitch.reason });
}

if (result.decision === "custom") {
  const payload = result.parsedValue ?? JSON.parse(result.value);
  return reply.send(payload);
}

Note: The SDK does not maintain rate-limit counters. It signals the throttle parameters; your infrastructure (Redis, middleware, etc.) is responsible for enforcement.


Custom Effects

A custom effect carries an arbitrary string — including a JSON-encoded object — back to the caller. Common uses: feature flags, A/B variants, per-tenant configuration overlays.

Enable automatic JSON parsing with engine.parseCustomEffect:

const client = new RuntimeClient({
  baseUrl:    "https://123456.runtime.govplane.com/",
  runtimeKey: process.env.GP_RUNTIME_KEY!,
  engine: {
    parseCustomEffect: true,   // JSON.parse() applied automatically
  },
});

const result = client.evaluate({ target, context });

if (result.decision === "custom") {
  const flags = result.parsedValue as { enabled: boolean; variant: string };
  if (flags?.enabled) renderNewCheckout();
}

Non-JSON strings leave parsedValue as undefined; the raw value string is always present as a fallback.


Conditional Rules (when / thenEffect / elseEffect)

Rules support an optional when condition AST evaluated against the call-time context. The AST is compiled by the control plane and distributed in the bundle — the SDK never executes dynamic code.

when absent           → always apply effect
when == true          → apply thenEffect   (fallback: effect)
when == false         → apply elseEffect   (fallback: skip rule)

Supported operators: eq, neq, gt, gte, lt, lte, in, exists, and, or, not.

The ctx. prefix on paths is optional and stripped automatically (ctx.planplan).


Policy Defaults

Every policy can declare a defaults object — the fallback effect when no rule matches that target. Defaults are treated as a synthetic rule with priority = -1, so any explicit rule always wins.

{
  "policyKey": "strict-rbac",
  "defaults":  { "effect": "deny" },
  "rules": [...]
}

All five effect types are supported as defaults: allow, deny, throttle, kill_switch, custom.


Runtime Bundle Model

The SDK retrieves compiled runtime bundles generated by the Govplane control plane.

type RuntimeBundleV1 = {
  schemaVersion:  1;
  orgId:          string;
  projectId:      string;
  env:            string;
  generatedAt:    string;       // ISO timestamp
  bundleVersion?: number;
  checksum?:      string;       // e.g. "sha256:..."
  policies:       RuntimePolicy[];
};

The bundle is treated as immutable and read-only. See Types & Interfaces for the full type tree.


Bundle Lifecycle & Polling

All evaluate() calls read from an in-memory cache — there is no network hop at decision time.

// Block until first bundle is ready, then start background polling
await client.warmStart({ timeoutMs: 10_000 });
client.start();

Polling strategy per cycle:

  1. HEAD the bundle endpoint to check the current ETag
  2. If ETag unchanged → update metadata, skip the GET
  3. If ETag changed → GET the full bundle, parse, update cache
  4. Notify onUpdate listeners

| Phase | Interval | |---|---| | Normal | pollMs (default 5 000 ms) | | Burst mode | burstPollMs (default 500 ms) for burstDurationMs (default 30 000 ms) | | Backoff | Exponential, capped at backoffMaxMs |

Bundle update subscription

client.onUpdate((result) => {
  logger.info("Bundle updated", {
    etag:          result.meta.etag,
    bundleVersion: result.meta.bundleVersion,
    updatedAt:     result.meta.updatedAt,
  });
});

Backoff & Degraded Mode

On repeated failures the client applies exponential backoff with jitter and enters degraded mode after a configurable number of consecutive failures. The cached bundle remains active in degraded mode.

const client = new RuntimeClient({
  ...
  backoffBaseMs:        500,
  backoffMaxMs:         30_000,
  backoffJitter:        0.2,
  degradeAfterFailures: 3,
});

client.onStatus((status) => {
  if (status.state === "degraded") {
    alerting.trigger("govplane_sdk_degraded", {
      failures:    status.consecutiveFailures,
      lastError:   status.lastError.message,
      nextRetryAt: status.nextRetryAt,
    });
  }
});

Backoff formula: delay = clamp(base × 2^(failures-1), 0, backoffMaxMs) ± jitter%


Context Policy & PII Safety

The context object is validated synchronously before every evaluation. A violation throws immediately, before any rule is tested.

const client = new RuntimeClient({
  ...
  engine: {
    contextPolicy: {
      allowedKeys:        ["plan", "role", "country", "isAuthenticated", "requestTier"],
      maxStringLen:       64,
      maxArrayLen:        10,
      blockLikelyPiiKeys: true,   // blocks email, phone, name, ip, ssn, etc.
    },
  },
});

Default allowed keys: plan, country, requestTier, feature, amount, isAuthenticated, role.

object values are not permitted at the top level. Permitted value types: string, number, boolean, null/undefined, string[].

Disable validation (engine: { validateContext: false }) only in controlled test environments.


Decision Tracing

Use evaluateWithTrace() to attach a DecisionTrace to the result for observability and debugging. Traces contain only structural metadata — no context values or PII.

Production (sampled)

const client = new RuntimeClient({
  ...
  trace: {
    defaults: {
      level:    "sampled",
      sampling: 0.05,   // 5% of evaluations
      budget:   { maxTraces: 60, windowMs: 60_000 },
    },
    onDecisionTraceAsync: async (evt) => {
      await analyticsClient.ingest("govplane.trace", evt);
    },
    queueMax:   1000,
    dropPolicy: "drop_new",
  },
});

const result = client.evaluateWithTrace({ target, context });
if (result.trace) {
  console.log(result.trace.summary);
  console.log(result.trace.winner);
}

Debug (forced)

const result = client.evaluateWithTrace(
  { target, context },
  { level: "full", force: true },   // bypass sampling and budget
);

| Level | Behaviour | |---|---| | "off" | No trace computed. Equivalent to evaluate(). | | "errors" | Trace attached only on deny or kill_switch. Compact format. | | "sampled" | Trace attached probabilistically by sampling rate and budget. Compact format. | | "full" | Always attempted (budget permitting). Includes complete per-rule list. |

Trace sinks

Both synchronous (onDecisionTrace) and async (onDecisionTraceAsync) sinks are supported. Async evaluations are buffered internally and never block evaluation. Drain on shutdown with client.flushTraces().

Trace guarantees

  • No rule bodies
  • No context values
  • No PII
  • Deterministic structure

Runtime Incident Controls

Govplane provides passive incident controls that allow operators to respond to incidents without exposing endpoints, handling PII, or recompiling application code.

| Mechanism | Restart Required | Hot | Recommended | |---|---|---|---| | Environment Variable (GP_RUNTIME_INCIDENT=1) | Usually yes | No | Yes | | File-based hot reload (incidentFilePath) | No | Yes | Primary | | POSIX Signal (SIGUSR1) | No | Yes | Optional |

const client = new RuntimeClient({
  ...
  incidentFilePath:   "/etc/govplane/incident.json",
  incidentFilePollMs: 1000,
  incidentSignal:     "SIGUSR1",
});

Incident file format:

{
  "burst":           true,
  "burstDurationMs": 60000,
  "burstPollMs":     200,
  "refreshNow":      true
}

See Incident Playbook and Incident Controls Reference for step-by-step procedures.


Using createPolicyEngine Directly

If you manage the bundle yourself (loaded from a file, injected from config), you can use the engine without RuntimeClient:

import { createPolicyEngine } from "@govplane/runtime-sdk";
import { readFileSync } from "node:fs";

const bundle = JSON.parse(readFileSync("bundle.json", "utf8"));

const engine = createPolicyEngine({
  getBundle:         () => bundle,
  parseCustomEffect: true,
  contextPolicy: {
    allowedKeys:        ["plan", "role"],
    maxStringLen:       64,
    maxArrayLen:        10,
    blockLikelyPiiKeys: true,
  },
});

const result = engine.evaluate({ target, context });

What This SDK Does NOT Do

  • No HTTP middleware
  • No inbound endpoints
  • No request interception
  • No PII handling or storage
  • No policy authoring
  • No dynamic code execution
  • No rate-limit counter maintenance

Security Notes

  • Runtime keys are read-only and scoped by org / project / env
  • Bundles are immutable — the SDK cannot modify control-plane state
  • Context validation and PII heuristic blocking are on by default
  • Safe to embed in critical paths

See Govplane Runtime SDK Threat Model for a full security analysis.


Documentation

| Topic | Link | |---|---| | Installation & Quick Start | docs/installation/GettingStarted.md | | Evaluating Decisions | docs/usage/Evaluate.md | | Effect Types | docs/usage/Effects.md | | Custom Effects | docs/usage/CustomEffect.md | | Conditional Rules | docs/usage/ConditionalRules.md | | Policy Defaults | docs/usage/PolicyDefaults.md | | Context Policy & PII Safety | docs/usage/ContextPolicy.md | | Bundle Lifecycle | docs/usage/BundleLifecycle.md | | Decision Tracing | docs/usage/DecisionTrace.md | | Configuration Reference | docs/reference/Configuration.md | | Types & Interfaces | docs/reference/TypesAndInterfaces.md | | Incident Playbook | docs/operations/Govplane_Incident_Playbook.md | | Incident Controls Reference | docs/operations/Govplane_Runtime_Incident_Controls.md | | Threat Model | docs/security/Govplane_Threat_Model.md |


License

MIT © Govplane