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

@helpful-insight/rbac

v1.0.3

Published

Enterprise Role-Based Access Control (RBAC) and Attribute-Based Access Control (ABAC) with wildcard permissions and Express guards

Downloads

291

Readme

@helpful-insight/rbac

npm version License: MIT TypeScript

Enterprise Role-Based Access Control (RBAC) and Attribute-Based Access Control (ABAC) engine for Node.js, Express, and Prisma. Features Role Inheritance & Hierarchy, Wildcard matching (*, users:*), Dynamic Contextual Rules (e.g. document ownership), Express route guards, and Prisma database adapters.


🌟 Key Features

  • 👑 Hierarchical Role Inheritance:
    • Roles can inherit from other roles (e.g. editor inherits from viewer, admin inherits from editor).
    • Circular dependency detection and resolution.
  • 🃏 Deep Wildcard Permission Matching:
    • Global wildcard: * (grants access to everything).
    • Segment wildcard: users:* (grants users:read, users:write, users:delete).
    • Multi-segment support: billing:invoices:*.
  • 🧠 Dynamic ABAC Contextual Rules:
    • Static permissions aren't always enough (e.g., "Users can edit posts ONLY if they are the author").
    • Register async/sync rules like isOwner, isDepartmentMember, isBusinessHours.
  • 🛡️ Express Route Guards:
    • Declarative middleware guards: guard.requirePermission('users:delete'), guard.requireRole('admin'), guard.requireRule('isOwner').
    • Returns standard HTTP 403 Forbidden with structured problem details.
  • 🗄️ Prisma Database Sync:
    • Load and synchronize roles, permissions, and user assignments directly from Prisma models.

📦 Installation

# npm
npm install @helpful-insight/rbac

# pnpm
pnpm add @helpful-insight/rbac

# yarn
yarn add @helpful-insight/rbac

🚀 Quick Start

import { RbacEngine } from '@helpful-insight/rbac';

// 1. Initialize RBAC with role hierarchy
const rbac = new RbacEngine([
  {
    name: 'viewer',
    permissions: ['posts:read', 'comments:read']
  },
  {
    name: 'editor',
    permissions: ['posts:create', 'posts:update'],
    inherits: ['viewer'] // inherits posts:read & comments:read
  },
  {
    name: 'admin',
    permissions: ['*'] // global wildcard
  }
]);

// 2. Check user permissions
const editorUser = { id: 'u_1', roles: ['editor'] };

console.log(rbac.canUser(editorUser, 'posts:read'));   // true (inherited from viewer)
console.log(rbac.canUser(editorUser, 'posts:create')); // true (direct permission)
console.log(rbac.canUser(editorUser, 'users:delete')); // false

const adminUser = { id: 'u_2', roles: ['admin'] };
console.log(rbac.canUser(adminUser, 'billing:invoices:destroy')); // true (wildcard *)

🧠 Dynamic ABAC (Ownership & Context)

When permissions depend on runtime attributes (e.g., resource author, department, or time):

// Register an ABAC ownership rule
rbac.registerRule('isPostAuthor', ({ user, resource }) => {
  return user.id === resource.authorId;
});

// Evaluate rule
const canEdit = await rbac.evaluateRule('isPostAuthor', {
  user: { id: 'user_100' },
  resource: { id: 'post_42', authorId: 'user_100' }
});

console.log(canEdit); // true

🌐 Express Route Guard Integration

Protect your Express endpoints cleanly with RbacGuard:

import express from 'express';
import { RbacEngine, RbacGuard } from '@helpful-insight/rbac';

const app = express();
app.use(express.json());

const rbac = new RbacEngine([
  { name: 'member', permissions: ['articles:read'] },
  { name: 'moderator', permissions: ['articles:delete'], inherits: ['member'] }
]);

const guard = new RbacGuard({ engine: rbac });

// 1. Require static permission (supports wildcards)
app.delete(
  '/api/articles/:id',
  guard.requirePermission('articles:delete'),
  (req, res) => {
    res.json({ message: 'Article deleted' });
  }
);

// 2. Require role directly
app.get(
  '/api/admin/metrics',
  guard.requireRole('admin'),
  (req, res) => {
    res.json({ status: 'ok' });
  }
);

// 3. Require dynamic ABAC rule
app.put(
  '/api/articles/:id',
  guard.requireRule(async ({ user, req }) => {
    // Check if user owns the article
    const article = await getArticleById(req.params.id);
    return article.authorId === user.id;
  }),
  (req, res) => {
    res.json({ message: 'Article updated' });
  }
);

Denied Response (HTTP 403 Forbidden):

{
  "success": false,
  "error": {
    "code": "FORBIDDEN",
    "message": "User lacks required permission: articles:delete"
  }
}

🗄️ Prisma Database Schema

model Role {
  id          String           @id @default(uuid())
  name        String           @unique
  description String?
  inherits    String?          // Comma-separated list of inherited role names
  permissions RolePermission[]
  users       UserRole[]
}

model Permission {
  id          String           @id @default(uuid())
  name        String           @unique // e.g. "users:delete", "posts:*"
  roles       RolePermission[]
}

model RolePermission {
  roleId       String
  permissionId String
  role         Role       @relation(fields: [roleId], references: [id], onDelete: Cascade)
  permission   Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)

  @@id([roleId, permissionId])
}

model UserRole {
  userId String
  roleId String
  role   Role   @relation(fields: [roleId], references: [id], onDelete: Cascade)

  @@id([userId, roleId])
}

📄 License

MIT © Helpful Insight Private Limited