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

@prodforcode/rbac-typeorm

v1.1.0

Published

TypeORM adapter for @prodforcode/rbac-core providing PostgreSQL/MySQL/SQLite database integration

Readme

@prodforcode/rbac-typeorm

TypeORM adapter for @prodforcode/rbac-core providing PostgreSQL, MySQL, and SQLite database integration.

Features

  • TypeORM Integration - Seamless integration with TypeORM ORM
  • Multiple Databases - PostgreSQL, MySQL, MariaDB, SQLite support
  • Entity Management - Pre-configured entities for roles, permissions, and audit logs
  • Migrations - Database migration scripts included
  • Repository Pattern - Type-safe repositories for all operations
  • Transaction Support - ACID-compliant operations
  • Indexes & Constraints - Optimized database schema with proper indexes

Installation

npm install @prodforcode/rbac-typeorm @prodforcode/rbac-core typeorm reflect-metadata
# or
yarn add @prodforcode/rbac-typeorm @prodforcode/rbac-core typeorm reflect-metadata
# or
pnpm add @prodforcode/rbac-typeorm @prodforcode/rbac-core typeorm reflect-metadata

Install database driver:

# PostgreSQL
npm install pg

# MySQL/MariaDB
npm install mysql2

# SQLite
npm install better-sqlite3

Quick Start

import { DataSource } from 'typeorm';
import { RBACEngine } from '@prodforcode/rbac-core';
import { TypeORMAdapter, entities } from '@prodforcode/rbac-typeorm';

// 1. Create TypeORM DataSource
const dataSource = new DataSource({
  type: 'postgres',
  host: 'localhost',
  port: 5432,
  username: 'admin',
  password: 'password',
  database: 'myapp',
  entities: entities,
  synchronize: false // Use migrations in production
});

await dataSource.initialize();

// 2. Create RBAC adapter
const adapter = new TypeORMAdapter(dataSource);

// 3. Initialize RBAC engine
const rbac = await RBACEngine.create({ adapter });

Database Setup

PostgreSQL

import { DataSource } from 'typeorm';
import { entities } from '@prodforcode/rbac-typeorm';

const dataSource = new DataSource({
  type: 'postgres',
  host: 'localhost',
  port: 5432,
  username: 'admin',
  password: 'password',
  database: 'myapp',
  entities: entities,
  synchronize: true, // Only for development
  logging: ['error', 'warn']
});

await dataSource.initialize();

MySQL/MariaDB

const dataSource = new DataSource({
  type: 'mysql',
  host: 'localhost',
  port: 3306,
  username: 'admin',
  password: 'password',
  database: 'myapp',
  entities: entities,
  synchronize: true,
  charset: 'utf8mb4'
});

SQLite

const dataSource = new DataSource({
  type: 'sqlite',
  database: './myapp.db',
  entities: entities,
  synchronize: true
});

Entities

The adapter provides five main entities:

RoleEntity

Represents roles in the system.

import { RoleEntity } from '@prodforcode/rbac-typeorm';

// Entity structure
class RoleEntity {
  id: string;                    // UUID primary key
  name: string;                  // Unique role name
  description: string | null;    // Optional description
  organizationId: string | null; // For multi-tenancy
  isActive: boolean;             // Active status
  metadata: Record<string, any>; // Custom metadata (JSONB)
  createdAt: Date;               // Creation timestamp
  updatedAt: Date;               // Last update timestamp

  // Relations
  permissions: RolePermissionEntity[];
  userRoles: UserRoleEntity[];
  parentRoles: RoleEntity[];
  childRoles: RoleEntity[];
}

PermissionEntity

Represents permissions that can be assigned to roles.

import { PermissionEntity } from '@prodforcode/rbac-typeorm';

class PermissionEntity {
  id: string;                    // UUID primary key
  resource: string;              // Resource name (e.g., 'posts')
  action: string;                // Action name (e.g., 'read')
  scope: string | null;          // Optional scope (e.g., 'own')
  description: string | null;    // Optional description
  conditions: Record<string, any> | null; // ABAC conditions
  createdAt: Date;
  updatedAt: Date;

  // Relations
  rolePermissions: RolePermissionEntity[];
}

RolePermissionEntity

Junction table linking roles and permissions.

import { RolePermissionEntity } from '@prodforcode/rbac-typeorm';

class RolePermissionEntity {
  id: string;
  roleId: string;
  permissionId: string;
  grantedAt: Date;
  grantedBy: string | null; // User ID who granted the permission

  // Relations
  role: RoleEntity;
  permission: PermissionEntity;
}

UserRoleEntity

Associates users with roles.

import { UserRoleEntity } from '@prodforcode/rbac-typeorm';

class UserRoleEntity {
  id: string;
  userId: string;
  roleId: string;
  organizationId: string | null; // For multi-tenancy
  assignedAt: Date;
  assignedBy: string | null; // User ID who assigned the role
  expiresAt: Date | null;    // Optional expiration

  // Relations
  role: RoleEntity;
}

AuditLogEntity

Tracks all RBAC operations for audit purposes.

import { AuditLogEntity } from '@prodforcode/rbac-typeorm';

class AuditLogEntity {
  id: string;
  action: string;           // e.g., 'ROLE_CREATED', 'PERMISSION_GRANTED'
  actorId: string | null;   // User who performed the action
  targetType: string;       // e.g., 'role', 'permission', 'user'
  targetId: string;         // ID of the target entity
  details: Record<string, any>; // Additional details (JSONB)
  severity: string;         // 'low', 'medium', 'high', 'critical'
  timestamp: Date;
}

Repositories

The adapter provides specialized repositories for database operations.

RoleRepository

import { RoleRepository } from '@prodforcode/rbac-typeorm';

const roleRepo = new RoleRepository(dataSource);

// Create a role
const role = await roleRepo.createRole({
  name: 'editor',
  description: 'Content editor role',
  organizationId: 'org-123'
});

// Find by name
const role = await roleRepo.findByName('editor', 'org-123');

// Get with permissions
const roleWithPerms = await roleRepo.findByIdWithPermissions(role.id);

// Update role
await roleRepo.updateRole(role.id, { description: 'Updated description' });

// Soft delete
await roleRepo.deactivateRole(role.id);

PermissionRepository

import { PermissionRepository } from '@prodforcode/rbac-typeorm';

const permRepo = new PermissionRepository(dataSource);

// Create permission
const permission = await permRepo.createPermission({
  resource: 'posts',
  action: 'write',
  scope: 'own',
  description: 'Write own posts'
});

// Find by resource and action
const perm = await permRepo.findByResourceAction('posts', 'write', 'own');

// Bulk create
const perms = await permRepo.bulkCreatePermissions([
  { resource: 'posts', action: 'read' },
  { resource: 'posts', action: 'write' },
  { resource: 'posts', action: 'delete' }
]);

UserRoleRepository

import { UserRoleRepository } from '@prodforcode/rbac-typeorm';

const userRoleRepo = new UserRoleRepository(dataSource);

// Assign role to user
await userRoleRepo.assignRole({
  userId: 'user-123',
  roleId: role.id,
  organizationId: 'org-123',
  assignedBy: 'admin-456'
});

// Get user's roles
const roles = await userRoleRepo.getUserRoles('user-123', 'org-123');

// Revoke role
await userRoleRepo.revokeRole('user-123', role.id, 'org-123');

// Check if user has role
const hasRole = await userRoleRepo.hasRole('user-123', role.id, 'org-123');

AuditRepository

import { AuditRepository } from '@prodforcode/rbac-typeorm';

const auditRepo = new AuditRepository(dataSource);

// Log an action
await auditRepo.log({
  action: 'ROLE_CREATED',
  actorId: 'admin-123',
  targetType: 'role',
  targetId: role.id,
  details: { roleName: 'editor' },
  severity: 'low'
});

// Query audit logs
const logs = await auditRepo.query({
  actorId: 'admin-123',
  startDate: new Date('2024-01-01'),
  limit: 100
});

Migrations

Generate Migration

npm run migration:generate -- -n CreateRBACTables

Run Migrations

npm run migration:run

Revert Migration

npm run migration:revert

Example Migration

import { MigrationInterface, QueryRunner } from 'typeorm';

export class CreateRBACTables1704067200000 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      CREATE TABLE "roles" (
        "id" uuid NOT NULL DEFAULT uuid_generate_v4(),
        "name" varchar(255) NOT NULL,
        "description" text,
        "organization_id" varchar(255),
        "is_active" boolean NOT NULL DEFAULT true,
        "metadata" jsonb NOT NULL DEFAULT '{}',
        "created_at" timestamp NOT NULL DEFAULT now(),
        "updated_at" timestamp NOT NULL DEFAULT now(),
        CONSTRAINT "PK_roles" PRIMARY KEY ("id"),
        CONSTRAINT "UQ_role_name_org" UNIQUE ("name", "organization_id")
      );

      CREATE INDEX "IDX_roles_organization" ON "roles" ("organization_id");
      CREATE INDEX "IDX_roles_is_active" ON "roles" ("is_active");
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP TABLE "roles"`);
  }
}

Transaction Support

Use TypeORM transactions for atomic operations:

import { TypeORMAdapter } from '@prodforcode/rbac-typeorm';

const adapter = new TypeORMAdapter(dataSource);

await dataSource.transaction(async (entityManager) => {
  // Create transactional adapter
  const txAdapter = new TypeORMAdapter(dataSource, entityManager);

  // All operations use the same transaction
  const role = await txAdapter.createRole({ name: 'editor' });
  await txAdapter.grantPermission(role.id, permission.id);
  await txAdapter.assignRole({ userId: 'user-123', roleId: role.id });

  // If any operation fails, entire transaction is rolled back
});

Multi-Tenancy

The adapter supports organization-scoped data:

// Create organization-specific role
const orgRole = await adapter.createRole({
  name: 'org-admin',
  organizationId: 'org-123'
});

// Assign role within organization
await adapter.assignRole({
  userId: 'user-456',
  roleId: orgRole.id,
  organizationId: 'org-123'
});

// Query organization-specific data
const orgRoles = await adapter.listRoles({ organizationId: 'org-123' });

Performance Optimization

Indexes

All entities include optimized indexes:

-- Role lookups
CREATE INDEX idx_roles_name ON roles(name);
CREATE INDEX idx_roles_organization ON roles(organization_id);

-- Permission lookups
CREATE INDEX idx_permissions_resource_action ON permissions(resource, action);

-- User role queries
CREATE INDEX idx_user_roles_user_org ON user_roles(user_id, organization_id);
CREATE INDEX idx_user_roles_role ON user_roles(role_id);

Query Optimization

// Use relation loading for efficient queries
const rolesWithPermissions = await roleRepo.find({
  relations: ['permissions', 'permissions.permission'],
  where: { organizationId: 'org-123' }
});

// Use query builder for complex queries
const roles = await dataSource
  .getRepository(RoleEntity)
  .createQueryBuilder('role')
  .leftJoinAndSelect('role.permissions', 'rp')
  .leftJoinAndSelect('rp.permission', 'perm')
  .where('role.organization_id = :orgId', { orgId: 'org-123' })
  .andWhere('role.is_active = :active', { active: true })
  .getMany();

Complete Example

import 'reflect-metadata';
import { DataSource } from 'typeorm';
import { RBACEngine } from '@prodforcode/rbac-core';
import { TypeORMAdapter, entities } from '@prodforcode/rbac-typeorm';

async function main() {
  // 1. Initialize database
  const dataSource = new DataSource({
    type: 'postgres',
    host: 'localhost',
    port: 5432,
    username: 'admin',
    password: 'password',
    database: 'myapp',
    entities: entities,
    synchronize: true,
    logging: true
  });

  await dataSource.initialize();
  console.log('Database connected');

  // 2. Create adapter and RBAC engine
  const adapter = new TypeORMAdapter(dataSource);
  const rbac = await RBACEngine.create({ adapter });

  // 3. Create roles
  const viewerRole = await rbac.createRole({
    name: 'viewer',
    permissions: ['posts:read', 'comments:read']
  });

  const editorRole = await rbac.createRole({
    name: 'editor',
    permissions: ['posts:*', 'comments:*'],
    parentRoles: [viewerRole.id]
  });

  // 4. Assign role to user
  await rbac.assignRole({
    userId: 'user-123',
    roleId: editorRole.id
  });

  // 5. Check permissions
  const canEdit = await rbac.can('user-123', 'posts:write');
  console.log('Can edit posts:', canEdit); // true

  // 6. Query audit logs
  const logs = await adapter.queryAuditLogs({
    limit: 10
  });
  console.log('Recent audit logs:', logs);
}

main().catch(console.error);

API Reference

TypeORMAdapter

class TypeORMAdapter implements IRBACAdapter {
  constructor(dataSource: DataSource, entityManager?: EntityManager);

  // Role operations
  async createRole(options: ICreateRoleOptions): Promise<IRole>;
  async updateRole(id: string, updates: IUpdateRoleOptions): Promise<IRole>;
  async deleteRole(id: string): Promise<boolean>;
  async findRoleById(id: string): Promise<IRole | null>;
  async findRoleByName(name: string, orgId?: string): Promise<IRole | null>;
  async listRoles(options?: ListRolesOptions): Promise<IRole[]>;

  // Permission operations
  async createPermission(options: ICreatePermissionOptions): Promise<IPermission>;
  async grantPermission(roleId: string, permissionId: string): Promise<void>;
  async revokePermission(roleId: string, permissionId: string): Promise<void>;

  // User role operations
  async assignRole(options: ICreateUserRoleOptions): Promise<IUserRoleAssignment>;
  async revokeRole(userId: string, roleId: string, orgId?: string): Promise<boolean>;
  async getUserRoles(userId: string, orgId?: string): Promise<IRole[]>;
  async getUserPermissions(userId: string, orgId?: string): Promise<IPermission[]>;

  // Audit operations
  async logAuditEntry(entry: ICreateAuditEntryOptions): Promise<IAuditEntry>;
  async queryAuditLogs(options: IAuditQueryOptions): Promise<IAuditQueryResult>;

  // Health check
  async healthCheck(): Promise<IAdapterHealthCheck>;
}

License

MIT