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

@aegis-runtime/aegisauth

v0.2.0

Published

Type-safe, explainable policy-as-code authorization engine with static route analysis for Node/TypeScript.

Downloads

69

Readme

AegisAuth

Type-safe, explainable policy-as-code authorization for TypeScript/Node, with a CLI that scans your routes and tells you which ones are missing authorization.

  • Centralized policies instead of scattered if (user.role === 'admin') checks
  • Explainable decisions: every allow/deny comes with human-readable reasons
  • Type-safe DSL for ctx and resource objects
  • Policy intelligence: introspection APIs, role-based summaries, rule metadata
  • Express adapter: authorize(engine, 'invoice', 'read', resolve)
  • Static analysis CLI: @aegis-runtime/aegisauth report src (+ --json) to flag routes without authorize()
  • OpenTelemetry integration: built-in observability for authorization decisions
  • Shadow testing: safely test new policies alongside production policies
  • ✅ No DB, queues, or external services required — pure TypeScript library

Table of Contents

  1. Architecture
  2. Tech Stack
  3. Motivation
  4. Core Concepts
  5. Installation
  6. Defining Policies
  7. Policy Intelligence & Introspection
  8. Making Decisions Manually
  9. Using the Express Adapter
  10. Advanced Features
  11. CLI: Route Authorization Report
  12. Examples & Project Structure
  13. Design Notes
  14. Roadmap
  15. License

Architecture

AegisAuth follows a layered architecture designed for flexibility, type safety, and observability:

┌─────────────────────────────────────────────────────────────┐
│                     Application Layer                        │
│  (Express Routes, RPC Handlers, Background Jobs, etc.)      │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        │ authorize() middleware / engine.decide()
                        │
┌───────────────────────▼─────────────────────────────────────┐
│                    Framework Adapters                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   Express    │  │  OpenTelemetry│  │   Shadow     │      │
│  │   Adapter    │  │   Integration │  │   Testing    │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        │ PolicyEngine API
                        │
┌───────────────────────▼─────────────────────────────────────┐
│                  Policy Engine Core                          │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  Rule Storage (Map<resourceType, Map<action, Rule[]>>)│   │
│  │  Decision Logic (deny-overrides semantics)            │   │
│  │  Introspection APIs (listRules, findRules, etc.)      │   │
│  │  Capability Snapshots                                  │   │
│  └──────────────────────────────────────────────────────┘   │
└───────────────────────┬─────────────────────────────────────┘
                        │
                        │ Type-safe DSL
                        │
┌───────────────────────▼─────────────────────────────────────┐
│                  Policy Definitions                          │
│  (Your domain-specific Ctx, Resources, and Rules)           │
└─────────────────────────────────────────────────────────────┘

Key Architectural Principles

  1. Separation of Concerns: The core engine is framework-agnostic; adapters bridge to specific frameworks (Express, OpenTelemetry, etc.)

  2. Type Safety: Full TypeScript generics ensure compile-time type checking for contexts, resources, and actions

  3. Extensibility: Hook-based architecture (onDecision, onDivergence) enables observability and custom behaviors

  4. Performance: In-memory rule evaluation with O(1) lookups by resource type and action

  5. Testability: Pure functions, no side effects, and deterministic decision logic make unit testing straightforward

Module Structure

@aegis-runtime/aegisauth
├── core (default export)
│   └── PolicyEngine, createPolicyEngine, Decision, RuleMeta
├── /express
│   └── authorize, authorizeWithShadow, AuthorizeOptions
├── /shadow
│   └── createShadowEngine, ShadowEngine, ShadowDivergenceInfo
└── /otel
    └── createPolicyEngineWithOtel, AegisAuthOtelOptions

Tech Stack

Core Technologies

  • TypeScript 5.5+: Full type safety, modern language features, and excellent IDE support
  • Node.js 18+: ESM support, modern JavaScript runtime
  • TypeScript Compiler API: Used by CLI for static analysis of route definitions

Build & Testing

  • TypeScript Compiler (tsc): Type checking and compilation
  • Vitest: Fast, modern testing framework
  • ESM (ES Modules): Native module system support

Runtime Dependencies

  • Zero runtime dependencies for the core engine
  • Peer dependencies:
    • express (^4.17.0 || ^5.0.0): For Express adapter
    • @opentelemetry/api (^1.9.0): For OpenTelemetry integration

Developer Experience

  • TypeScript strict mode: Maximum type safety
  • Declaration files (.d.ts): Full type information for consumers
  • Tree-shakeable exports: Modern bundlers can eliminate unused code
  • Side-effect free: Safe for tree-shaking and module optimization

Observability & Monitoring

  • OpenTelemetry: Standard observability protocol
    • Metrics: Decision counts, latency histograms
    • Traces: Spans for each authorization decision
    • Attributes: Resource type, action, outcome, reasons

Motivation

Authorization (authZ) answers the question: "What is this user allowed to do?"

In most Node/TypeScript backends, authorization logic:

  • Is scattered across controllers and services
  • Is written as ad-hoc conditionals like if (user.role === 'admin') everywhere
  • Has no single source of truth for "who can do what"
  • Is hard to test, hard to audit, and hard to change safely

AegisAuth aims to fix this by providing:

  1. A central policy engine where you define all your rules as code
  2. A type-safe DSL for expressing permissions with context and resources
  3. Explainable decisions, with reasons returned for each allow/deny
  4. An Express adapter to protect routes via middleware
  5. A CLI that statically scans your code for routes that lack authorization
  6. A policy intelligence layer to introspect and summarize your rules
  7. OpenTelemetry integration for production observability
  8. Shadow testing capabilities for safe policy migrations

The goal is to treat authorization as first-class, testable, auditable code rather than scattered if statements.


Core Concepts

AegisAuth revolves around four core ideas:

1. Context (Ctx)

Represents who is making the request and global request context.

type Ctx = {
  user: {
    id: string;
    orgId: string;
    roles: string[];
  } | null;
};

You decide the shape of Ctx for your application.

2. Resources (Resources)

Represents the domain objects you protect, such as Invoice, Project, Organization, etc.

interface Invoice {
  id: string;
  orgId: string;
  status: 'draft' | 'paid';
}

interface Resources {
  invoice: Invoice;
}

Each resource type is referenced by a string key (e.g. 'invoice').

3. Policies

Policies answer "Who can perform which action on which resource, under which conditions?"

You express policies with a fluent, type-safe DSL:

engine
  .forResource('invoice')
  .can('read')
    .when((ctx, invoice) => !!ctx.user && ctx.user.orgId === invoice.orgId)
    .because('User belongs to same organization as the invoice')
  .can('delete')
    .when((ctx, invoice) => !!ctx.user && ctx.user.roles.includes('admin'))
    .because('Admins can delete invoices in their org')
  .cannot('delete')
    .when((_ctx, invoice) => invoice.status === 'paid')
    .because('Paid invoices cannot be deleted for compliance');

At runtime, AegisAuth evaluates policies to produce a Decision:

interface Decision {
  allowed: boolean;
  reasons: string[];
  matchedRuleIds: string[];
}
  • allowed – final yes/no answer
  • reasons – human-readable explanations
  • matchedRuleIds – internal rule IDs (helpful for debugging and audits)

AegisAuth uses deny-overrides semantics: any matching cannot rule will deny access, even if a can rule also matches.

4. Rule Metadata & Policy Intelligence

Each rule can carry structured metadata for analysis:

engine
  .forResource('invoice')
  .can('delete')
    .when((ctx, invoice) =>
      !!ctx.user &&
      ctx.user.roles.includes('admin') &&
      ctx.user.orgId === invoice.orgId
    )
    .because('Admins can delete invoices in their org', {
      roles: ['admin'],
      tags: ['invoice', 'delete'],
      severity: 'high',
      descriptionId: 'INV-DEL-001',
    });

This metadata drives the introspection APIs and lets you answer questions like:

  • "What can admin do in this system?"
  • "Which rules are high-severity and related to invoices?"

Installation

Install from npm:

npm install @aegis-runtime/aegisauth

If you use the Express adapter, also install Express:

npm install express

If you use OpenTelemetry integration, also install:

npm install @opentelemetry/api

AegisAuth is ESM-only and targets Node 18+. express and @opentelemetry/api are peer dependencies; the library does not bundle them.


Defining Policies

You start by creating a policy engine with your own Ctx and Resources types.

import { createPolicyEngine } from '@aegis-runtime/aegisauth';

interface User {
  id: string;
  orgId: string;
  roles: string[];
}

interface Invoice {
  id: string;
  orgId: string;
  status: 'draft' | 'paid';
}

type Ctx = { user: User | null };

interface Resources {
  invoice: Invoice;
}

export const engine = createPolicyEngine<Ctx, Resources>();

engine
  .forResource('invoice')
  .can('read')
    .when((ctx, invoice) => !!ctx.user && ctx.user.orgId === invoice.orgId)
    .because('User belongs to same organization as the invoice', {
      roles: ['user'],
      tags: ['invoice', 'read'],
    })
  .can('delete')
    .when((ctx, invoice) =>
      !!ctx.user &&
      ctx.user.roles.includes('admin') &&
      ctx.user.orgId === invoice.orgId
    )
    .because('Admins can delete invoices in their org', {
      roles: ['admin'],
      tags: ['invoice', 'delete'],
      severity: 'high',
    })
  .cannot('delete')
    .when((_ctx, invoice) => invoice.status === 'paid')
    .because('Paid invoices cannot be deleted for compliance', {
      tags: ['invoice', 'delete', 'compliance'],
      severity: 'high',
    });

API Overview

  • createPolicyEngine<Ctx, Resources>() – create an engine
  • engine.forResource('invoice') – start defining rules for a resource type
  • .can(action) / .cannot(action) – define allow/deny rules for an action
  • .when((ctx, resource) => boolean) – attach a condition (optional)
  • .because(description, meta?) – finalize the rule with a human-readable explanation and optional metadata

If you omit .when(...), the rule is treated as unconditional (always true).


Policy Intelligence & Introspection

AegisAuth exposes introspection APIs so you can treat authorization as data, not just behavior.

Rule Metadata Type

interface RuleMeta {
  roles?: string[];
  tags?: string[];
  severity?: 'low' | 'medium' | 'high';
  descriptionId?: string;
  [key: string]: any;
}

Listing All Rules

const rules = engine.listRules();
/*
[
  {
    id: 'invoice:read:1',
    resourceType: 'invoice',
    action: 'read',
    effect: 'allow',
    description: 'User belongs to same organization as the invoice',
    meta: { roles: ['user'], tags: ['invoice', 'read'] }
  },
  ...
]
*/

Finding Rules by Predicate

const highRiskInvoiceRules = engine.findRules(
  (r) =>
    r.resourceType === 'invoice' &&
    r.meta?.severity === 'high'
);

Summarizing by Role

const adminSummary = engine.summarizeByRole('admin');

/*
[
  {
    role: 'admin',
    resourceType: 'invoice',
    action: 'delete',
    effect: 'allow',
    description: 'Admins can delete invoices in their org'
  },
  ...
]
*/

Capability Snapshots

Generate capability matrices for batches of resources:

const snapshot = engine.snapshotCapabilities({
  ctx: { user: adminUser },
  resources: {
    invoice: [invoice1, invoice2, invoice3],
  },
  version: '1.0.0',
});

// snapshot.capabilities['invoice']['delete'] = [true, false, true]
// → invoice1: can delete, invoice2: cannot, invoice3: can delete

You can expose this internally as a JSON endpoint, generate Markdown docs, or feed it into a dashboard.


Making Decisions Manually

You can call the engine directly (e.g. in services, background jobs, or tests):

import type { Decision } from '@aegis-runtime/aegisauth';
import { engine } from './policies';

const ctx: Ctx = {
  user: { id: 'u1', orgId: 'org1', roles: ['admin'] },
};

const invoice: Invoice = {
  id: 'inv1',
  orgId: 'org1',
  status: 'draft',
};

const decision: Decision = engine.decide({
  resourceType: 'invoice',
  action: 'delete',
  ctx,
  resource: invoice,
});

if (decision.allowed) {
  // proceed
} else {
  console.log('Denied because:', decision.reasons);
}

Behavior:

  • If any cannot rule matches, the decision is denied.
  • Else if any can rule matches, the decision is allowed.
  • If no rule matches, the decision is an implicit deny.
  • If no rules exist for the given resource/action, AegisAuth returns a helpful reason message.

Using the Express Adapter

AegisAuth ships an Express middleware adapter that wires the engine into HTTP routes.

1. Import the adapter

import { authorize } from '@aegis-runtime/aegisauth/express';
import { engine } from '../auth/policies';

2. Protect a route

import express from 'express';

const router = express.Router();

router.delete(
  '/:id',
  authorize(engine, 'invoice', 'delete', async (req) => {
    const user = req.user as User | null; // from your auth middleware
    const invoice = await loadInvoiceFromDb(req.params.id);

    return { ctx: { user }, resource: invoice };
  }),
  async (req, res) => {
    const invoice = res.locals.resource as Invoice;
    await deleteInvoice(invoice.id);
    res.status(204).send();
  }
);

3. Middleware signature

function authorize<
  Ctx,
  Resources extends Record<string, any>,
  K extends keyof Resources & string
>(
  engine: PolicyEngine<Ctx, Resources>,
  resourceType: K,
  action: string,
  resolve: (req: Request) =>
    | { ctx: Ctx; resource: Resources[K] }
    | Promise<{ ctx: Ctx; resource: Resources[K] }>,
  options?: AuthorizeOptions<Ctx, Resources, K>
): RequestHandler;

At runtime:

  1. resolve(req) is called to build { ctx, resource }.

  2. engine.decide({ resourceType, action, ctx, resource }) is executed.

  3. If denied:

    • Default: responds with 403 and { error, reasons } JSON
    • Or, if options.onDeny is provided, your custom handler is called
  4. If allowed:

    • Decision is attached to res.locals[attachKey] (default: 'authDecision')
    • Resource is attached to res.locals.resource (optional)
    • next() is called

4. Customizing behavior

import { authorize } from '@aegis-runtime/aegisauth/express';

router.post(
  '/',
  authorize(
    engine,
    'invoice',
    'create',
    async (req) => ({
      ctx: { user: req.user as User | null },
      resource: req.body as Invoice,
    }),
    {
      onDeny: (req, res, decision) => {
        res.status(401).json({
          error: 'Not allowed to create invoices',
          reasons: decision.reasons,
        });
      },
      attachDecisionTo: 'locals',   // or 'request'
      attachKey: 'invoiceDecision', // res.locals.invoiceDecision
      attachResource: true,
    }
  )
);

Advanced Features

OpenTelemetry Integration

AegisAuth provides built-in OpenTelemetry integration for production observability.

Setup

import { createPolicyEngineWithOtel } from '@aegis-runtime/aegisauth/otel';
import { Meter, Tracer } from '@opentelemetry/api';

// In your OpenTelemetry setup
const meter = /* your OpenTelemetry Meter */;
const tracer = /* your OpenTelemetry Tracer */;

const engine = createPolicyEngineWithOtel({
  meter,
  tracer, // optional
  defaultAttributes: {
    'service.name': 'invoice-service',
    'service.version': '1.0.0',
  },
});

// Use the engine normally - metrics and traces are emitted automatically
engine.forResource('invoice')
  .can('read')
  .because('User can read invoices');

Metrics Emitted

  • aegisauth_decisions_total (Counter): Total number of authorization decisions
    • Attributes: aegisauth.resource_type, aegisauth.action, aegisauth.allowed
  • aegisauth_decision_duration_ms (Histogram): Latency of authorization decisions
    • Unit: milliseconds
    • Attributes: Same as counter

Traces Emitted (if tracer provided)

  • Span name: aegisauth.decision
  • Attributes:
    • aegisauth.resource_type
    • aegisauth.action
    • aegisauth.allowed
    • aegisauth.reasons (joined with |)
    • aegisauth.matched_rule_ids (joined with ,)
    • Plus any defaultAttributes you provided

This enables monitoring authorization decisions in production, alerting on policy violations, and debugging authorization issues.

Shadow Testing

Shadow testing allows you to evaluate a candidate policy engine alongside your production engine without affecting user requests. This is invaluable for:

  • Testing new policies before deployment
  • Validating policy migrations
  • A/B testing authorization rules
  • Detecting policy regressions

Setup

import { createShadowEngine } from '@aegis-runtime/aegisauth/shadow';
import { authorizeWithShadow } from '@aegis-runtime/aegisauth/express';

// Your current production engine
const currentEngine = createPolicyEngine<Ctx, Resources>();
// ... define current policies

// Your candidate engine with new/changed policies
const candidateEngine = createPolicyEngine<Ctx, Resources>();
// ... define candidate policies

const shadowEngine = createShadowEngine({
  current: currentEngine,
  candidate: candidateEngine,
  onDivergence: (info) => {
    // Log or alert when decisions diverge
    console.warn('Policy divergence detected:', {
      resourceType: info.resourceType,
      action: info.action,
      current: info.current.allowed,
      candidate: info.candidate.allowed,
      currentReasons: info.current.reasons,
      candidateReasons: info.candidate.reasons,
    });
    
    // Send to monitoring/alerting system
    // metrics.recordDivergence(info);
  },
});

// Use shadow engine in routes - current engine's decision is enforced,
// but candidate is evaluated in parallel
router.delete(
  '/:id',
  authorizeWithShadow(shadowEngine, 'invoice', 'delete', async (req) => {
    const user = req.user as User | null;
    const invoice = await loadInvoiceFromDb(req.params.id);
    return { ctx: { user }, resource: invoice };
  }),
  async (req, res) => {
    // ... handler
  }
);

How It Works

  1. Current engine's decision is enforced: Users experience the behavior of your current policies
  2. Candidate engine is evaluated in parallel: The candidate engine's decision is computed but not used
  3. Divergences are reported: If decisions differ, onDivergence is called with both decisions
  4. Zero user impact: Even if the candidate engine would deny access, the user's request proceeds based on the current engine

Divergence Detection

A divergence is detected when:

  • currentDecision.allowed !== candidateDecision.allowed, OR
  • The matched rule IDs differ, OR
  • The reasons differ

This allows you to catch subtle policy changes that might affect authorization behavior.

Decision Hooks

You can also use the onDecision hook on individual engines to capture timing and metrics:

const engine = createPolicyEngine({
  onDecision: (info) => {
    console.log(`Decision took ${info.elapsedMs}ms`);
    // Custom metrics, logging, etc.
  },
});

CLI: Route Authorization Report

The CLI scans your TypeScript source files for Express routes and reports which ones use authorize(...).

1. Human-readable report

From your project root (where your routes live):

npx @aegis-runtime/aegisauth report src

Example output:

Scanning routes under: /path/to/project/src

AegisAuth route authorization report
------------------------------------

[ OK ]  GET    /invoices/:id        src/routes/invoices.ts:10
[ OK ]  DELETE /invoices/:id        src/routes/invoices.ts:30
[ !! ]  POST   /invoices            src/routes/invoices.ts:45

Summary:
  Total routes:          3
  Protected (authorize): 2
  Missing authorize:     1
  • [ OK ] – route has at least one handler using authorize(...)
  • [ !! ] – route has no authorize(...) handler detected

If any route is missing authorization, the CLI returns exit code 1.

This is ideal for CI:

# GitHub Actions example
- name: AegisAuth route report
  run: npx @aegis-runtime/aegisauth report src

2. JSON mode for tooling / dashboards

You can also get machine-readable JSON:

npx @aegis-runtime/aegisauth report src --json > aegisauth-report.json

Example JSON shape:

{
  "root": "/absolute/path/to/src",
  "routes": [
    {
      "method": "GET",
      "path": "/invoices/:id",
      "file": "/absolute/path/to/src/routes/invoices.ts",
      "line": 10,
      "authorized": true
    },
    {
      "method": "POST",
      "path": "/invoices",
      "file": "/absolute/path/to/src/routes/invoices.ts",
      "line": 45,
      "authorized": false
    }
  ],
  "summary": {
    "total": 3,
    "protected": 2,
    "missing": 1
  }
}

3. Diff Reports

Compare two reports to detect regressions:

npx @aegis-runtime/aegisauth report src --json > report.old.json
# ... make changes ...
npx @aegis-runtime/aegisauth report src --json > report.new.json
npx @aegis-runtime/aegisauth diff report.old.json report.new.json

Output shows routes that gained or lost authorization protection.

You can:

  • Upload this as a CI artifact
  • Feed it into a dashboard
  • Diff it between branches to see how coverage changes

4. What the CLI recognizes

The CLI currently supports Express-style route definitions:

app.get('/path', handler);
router.post('/path', handler1, handler2);

It looks for imports like:

import { authorize } from '@aegis-runtime/aegisauth/express';
import { authorize as aegisAuthorize } from '@aegis-runtime/aegisauth/express';

If any handler argument in the route call uses one of these authorize identifiers, that route is considered protected.

The CLI does not execute your code; it performs static analysis using the TypeScript compiler API.


Examples & Project Structure

A typical usage structure might look like:

src/
  auth/
    policies.ts        # all AegisAuth policies live here
  routes/
    invoices.ts        # Express routes using authorize(engine, ...)
  db/
    invoices.ts        # DB accessors
  server.ts            # app bootstrap
  • auth/policies.ts

    • Defines Ctx, Resources, and all rules
    • Is the single source of truth for authorization
  • routes/*.ts

    • Import authorize from @aegis-runtime/aegisauth/express
    • Wire policies into HTTP handlers via middleware
  • CI config

    • Runs npx @aegis-runtime/aegisauth report src (optionally with --json) to ensure all routes are protected

Design Notes

1. Deny-overrides semantics

AegisAuth adopts a simple yet robust model:

  • If any deny rule (cannot) matches, the final decision is deny.
  • Otherwise, if any allow rule (can) matches, the final decision is allow.
  • If no rule matches, the result is an implicit deny with a clear reason.

This mirrors common practices in secure systems (deny is sticky and safer).

2. Type-safe DSL

The engine is generic over Ctx and Resources, so:

  • You get full TypeScript type-checking inside when((ctx, resource) => ...)
  • Mistyped fields on your resource or ctx are caught at compile time
  • You define policies in terms of your actual domain types

3. No runtime dependencies in the core

The core engine:

  • Has no external runtime dependencies
  • Does not require a database, cache, or message queue
  • Is pure, deterministic logic → easy to test and reason about

The CLI is a separate concern, built on top of the TypeScript compiler API.

4. Express-first, framework-agnostic

The included adapter targets Express because it's widely used, but the engine itself is framework-agnostic:

  • You can use engine.decide(...) in Nest, Fastify, RPC handlers, cron jobs, etc.
  • Thin adapters for other frameworks can be built easily.

5. Performance Characteristics

  • Rule lookup: O(1) by resource type and action (Map-based storage)
  • Decision evaluation: O(n) where n is the number of rules for the resource/action pair
  • Memory: O(r) where r is the total number of rules
  • No I/O: All decisions are synchronous and in-memory

Typical authorization decisions complete in microseconds, making AegisAuth suitable for high-throughput applications.


Roadmap

Planned and potential enhancements:

  • Policy testing helpers Utilities for writing focused unit tests and fixtures for complex policies.

  • More framework adapters Fastify, NestJS decorators, RPC middleware, etc.

  • Richer analysis & reporting

    • Mapping routes to specific (resource, action) pairs
    • HTML/Markdown report generation
  • Policy Explorer UI A small React app that ingests @aegis-runtime/aegisauth report --json + engine.listRules() and renders a role/action matrix.

  • IDE integration VS Code extension to visualize which policies apply to a given route or role.

  • Policy versioning Built-in support for policy versioning and migration strategies.

  • Rule composition Higher-level abstractions for common patterns (RBAC, ABAC, etc.).

If you have use cases or ideas, feel free to open an issue or PR.


License

MIT. Use it freely in commercial and open-source projects.