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 🙏

© 2025 – Pkg Stats / Ryan Hefner

rbac-react-system

v1.0.4

Published

Enterprise-grade Role-Based Access Control library for React with Clean Architecture

Readme

rbac-react-system

Библиотека управления доступом на основе ролей (RBAC) для React с чистой архитектурой

Версия: 1.0.4 Дата: 2025-11-30 Автор: TM Project Лицензия: MIT

npm version License: MIT TypeScript pipeline status coverage report

🎯 Функции

  • Чистая архитектура - Полное разделение бизнес-логики от React фреймворка
  • TypeScript - Полная типизация со строгим режимом
  • Без зависимостей - Только React как peer dependency
  • Гибкий API - Несколько способов использования (хуки, HOC, компоненты)
  • Продвинутое RBAC - Наследование ролей, условные разрешения, динамические условия
  • Tree Shakable - Оптимизированные ES модули с минимальным размером бандла
  • SSR совместимость - Работает со server-side rendering
  • Двойной формат - Поддержка ESM и CommonJS

📦 Установка

npm install rbac-react-system
yarn add rbac-react-system
pnpm add rbac-react-system

🚀 Быстрый старт

1. Настройка провайдера

Оберните приложение компонентом RbacProvider:

import { RbacProvider } from 'rbac-react-system'
import {
  MockUserRepository,
  MockRoleRepository,
  MockPermissionRepository
} from 'rbac-react-system'

const userRepository = new MockUserRepository([
  {
    id: 'user-1',
    roles: ['admin'],
    permissions: ['posts:read', 'posts:write'],
    attributes: { department: 'IT' }
  }
])

const roleRepository = new MockRoleRepository([
  {
    id: 'admin',
    name: 'Администратор',
    permissions: [
      { id: 'p1', resource: 'users', action: 'read' },
      { id: 'p2', resource: 'users', action: 'write' }
    ],
    inheritedRoles: ['editor']
  }
])

const permissionRepository = new MockPermissionRepository()

export function App() {
  return (
    <RbacProvider
      config={{
        userRepository,
        roleRepository,
        permissionRepository,
        initialUserId: 'user-1'
      }}
    >
      <YourApp />
    </RbacProvider>
  )
}

2. Используйте хуки

import { useAccess, usePermission, useRole } from 'rbac-react-system'

function UserProfile() {
  const canEditProfile = useAccess('users', 'write')
  const hasAdminRole = useRole('admin')
  const canDeletePosts = usePermission('posts:delete')

  return (
    <div>
      {canEditProfile && <button>Редактировать профиль</button>}
      {hasAdminRole && <AdminPanel />}
      {canDeletePosts && <button>Удалить пост</button>}
    </div>
  )
}

3. Используйте компоненты

import { Protected } from 'rbac-react-system'

function Dashboard() {
  return (
    <div>
      <Protected
        resource="analytics"
        action="view"
        fallback={<div>Доступ запрещен</div>}
      >
        <AnalyticsDashboard />
      </Protected>
    </div>
  )
}

4. Используйте HOC

import { withPermission, withRole } from 'rbac-react-system'

const AdminSettings = withRole('admin', {
  fallback: <div>Требуется доступ администратора</div>
})(SettingsComponent)

const UserEditor = withPermission('users:write')(EditorComponent)

📚 Основные концепции

Архитектура

Библиотека следует принципам Clean Architecture с четырьмя слоями:

┌──────────────────────────────────────┐
│      Слой представления (React)      │
│   (Хуки, HOC, Компоненты)            │
└──────────────────┬───────────────────┘
                   │
┌──────────────────▼───────────────────┐
│      Прикладной слой                 │
│   (Use Cases, Services)              │
└──────────────────┬───────────────────┘
                   │
┌──────────────────▼───────────────────┐
│       Доменный слой                  │
│  (Сущности, Интерфейсы, Исключения)  │
└──────────────────────────────────────┘
                   ▲
┌──────────────────┴───────────────────┐
│  Инфраструктурный слой               │
│  (Реализации репозиториев)           │
└──────────────────────────────────────┘

Сущности

User (Пользователь)

Представляет пользователя в системе RBAC:

interface User {
  id: string
  roles: string[]
  permissions: string[]
  attributes: Record<string, unknown>
  metadata?: Record<string, unknown>
}

Role (Роль)

Группирует разрешения и поддерживает наследование:

interface Role {
  id: string
  name: string
  permissions: Permission[]
  inheritedRoles?: string[]
  metadata?: Record<string, unknown>
}

Permission (Разрешение)

Определяет доступ к ресурсу с возможными условиями:

interface Permission {
  id: string
  action: string
  resource: string
  conditions?: Condition[]
  metadata?: Record<string, unknown>
}

Condition (Условие)

Динамический контроль доступа на основе контекста:

interface Condition {
  id: string
  type: string
  field: string
  operator: 'equals' | 'notEquals' | 'contains' | 'greaterThan' | 'lessThan' | 'in' | 'notIn'
  value: string | number | boolean | string[] | number[]
  metadata?: Record<string, unknown>
}

📖 Справочник API

Провайдер

RbacProvider

<RbacProvider config={config}>
  {children}
</RbacProvider>

Свойства:

  • config: RbacConfig - Объект конфигурации
    • userRepository: Реализация IUserRepository
    • roleRepository: Реализация IRoleRepository
    • permissionRepository: Реализация IPermissionRepository
    • initialUserId?: ID пользователя для загрузки при инициализации

Хуки

useRbac

Возвращает полный контекст RBAC:

const {
  user,
  isLoading,
  error,
  canAccess,
  hasRole,
  hasPermission,
  refreshPermissions,
  setUser
} = useRbac()

Пример:

function Dashboard() {
  const { user, isLoading, canAccess } = useRbac()

  if (isLoading) return <Spinner />

  const handleDelete = async () => {
    const allowed = await canAccess('posts', 'delete')
    if (allowed) {
      // Удалить пост
    }
  }

  return <button onClick={handleDelete}>Удалить</button>
}

useAccess

Проверяет доступ к ресурсу с действием:

const canDelete = useAccess('posts', 'delete')

Пример:

function PostActions({ post }) {
  const canEdit = useAccess('posts', 'edit')
  const canDelete = useAccess('posts', 'delete')

  return (
    <div>
      {canEdit && <button>✏️ Редактировать</button>}
      {canDelete && <button>🗑️ Удалить</button>}
    </div>
  )
}

usePermission

Проверяет прямое разрешение:

const hasPermission = usePermission('posts:delete')

Пример:

function AdminFeature() {
  const hasAdminAccess = usePermission('admin:access')

  return hasAdminAccess ? <AdminPanel /> : null
}

useRole

Проверяет членство в роли:

const isAdmin = useRole('admin')

Пример:

function UserGreeting() {
  const isAdmin = useRole('admin')
  const isEditor = useRole('editor')

  return (
    <div>
      <p>Добро пожаловать!</p>
      {isAdmin && <p>Вы администратор 👑</p>}
      {isEditor && <p>Вы редактор 📝</p>}
    </div>
  )
}

Компоненты

Protected

Условный рендеринг на основе разрешений:

<Protected
  resource="users"
  action="read"
  fallback={<AccessDenied />}
  loading={<Spinner />}
>
  <UserList />
</Protected>

Свойства:

  • resource: string - Название ресурса
  • action: string - Название действия
  • fallback?: ReactNode - Рендерится когда доступ запрещен
  • loading?: ReactNode - Рендерится во время проверки доступа
  • children: ReactNode - Рендерится когда доступ разрешен

Пример:

function SettingsPanel() {
  return (
    <div>
      <Protected resource="settings" action="read">
        <h2>Параметры</h2>
        <SettingsList />
      </Protected>

      <Protected
        resource="settings"
        action="write"
        fallback={<p>Редактирование недоступно</p>}
      >
        <SettingsEditor />
      </Protected>
    </div>
  )
}

HOC (Higher-Order Components)

withPermission

withPermission<Props>(
  permission: string,
  options?: { fallback?: ReactNode }
)

Пример:

const AdminPanel = withPermission('admin:access', {
  fallback: <div>⛔ Только для администраторов</div>
})(AdminComponent)

// Использование:
<AdminPanel someProps="value" />

withRole

withRole<Props>(
  role: string,
  options?: { fallback?: ReactNode }
)

Пример:

const EditorPanel = withRole('editor', {
  fallback: <div>⛔ Только для редакторов</div>
})(EditorComponent)

// Использование:
<EditorPanel someProps="value" />

🔧 Продвинутое использование

Custom репозиторий (REST API)

Замените mock репозитории на ваши собственные реализации:

import { IUserRepository, User } from 'rbac-react-system'

class ApiUserRepository implements IUserRepository {
  async findUserById(userId: string): Promise<User | null> {
    try {
      const response = await fetch(`/api/users/${userId}`)
      if (!response.ok) return null
      return await response.json()
    } catch (error) {
      console.error('Failed to fetch user:', error)
      return null
    }
  }

  async getUserRoles(userId: string): Promise<string[]> {
    try {
      const response = await fetch(`/api/users/${userId}/roles`)
      return await response.json()
    } catch (error) {
      console.error('Failed to fetch roles:', error)
      return []
    }
  }

  async updateUser(userId: string, userData: Partial<User>): Promise<User> {
    const response = await fetch(`/api/users/${userId}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(userData)
    })
    return await response.json()
  }
}

Условные разрешения (Conditions)

Определите разрешения с условиями:

const permission = {
  id: 'edit-own-posts',
  resource: 'posts',
  action: 'edit',
  conditions: [
    {
      id: 'c1',
      type: 'attribute-based',
      field: 'department',
      operator: 'equals',
      value: 'Content'
    }
  ]
}

Пример с временными ограничениями:

const permission = {
  id: 'docs-read-business-hours',
  resource: 'documents',
  action: 'read',
  conditions: [
    {
      id: 'time-check',
      type: 'time-based',
      field: 'currentHour',
      operator: 'in',
      value: [9, 10, 11, 12, 13, 14, 15, 16, 17] // 9:00 - 17:00
    }
  ]
}

Наследование ролей

Создайте иерархию ролей:

const roles = [
  {
    id: 'viewer',
    name: 'Зритель',
    permissions: [{ id: 'p1', resource: 'posts', action: 'read' }]
  },
  {
    id: 'editor',
    name: 'Редактор',
    permissions: [{ id: 'p2', resource: 'posts', action: 'write' }],
    inheritedRoles: ['viewer'] // Наследует все разрешения зрителя
  },
  {
    id: 'admin',
    name: 'Администратор',
    permissions: [{ id: 'p3', resource: 'posts', action: 'delete' }],
    inheritedRoles: ['editor'] // Наследует разрешения редактора и зрителя
  }
]

Динамическое переключение пользователей

function UserSwitcher() {
  const { setUser, isLoading } = useRbac()

  const switchUser = async (userId: string) => {
    await setUser(userId)
  }

  return (
    <select onChange={(e) => switchUser(e.target.value)}>
      <option value="user-1">Пользователь 1</option>
      <option value="user-2">Пользователь 2</option>
      <option value="user-3">Администратор</option>
    </select>
  )
}

Обновление разрешений

function RefreshPermissions() {
  const { refreshPermissions, isLoading } = useRbac()

  return (
    <button onClick={() => refreshPermissions()} disabled={isLoading}>
      {isLoading ? 'Обновление...' : 'Обновить разрешения'}
    </button>
  )
}

📝 Примеры

Защищенные маршруты

import { useAccess } from 'rbac-react-system'
import { Navigate } from 'react-router-dom'

function ProtectedRoute({ children, resource, action }) {
  const hasAccess = useAccess(resource, action)

  if (!hasAccess) {
    return <Navigate to="/unauthorized" />
  }

  return children
}

// Использование
<Route
  path="/admin"
  element={
    <ProtectedRoute resource="admin" action="access">
      <AdminDashboard />
    </ProtectedRoute>
  }
/>

Условные элементы UI

function PostActions({ post }) {
  const canEdit = useAccess('posts', 'edit')
  const canDelete = useAccess('posts', 'delete')
  const isAuthor = usePermission(`posts:${post.id}:edit`)

  return (
    <div>
      {canEdit && isAuthor && <button>✏️ Редактировать</button>}
      {canDelete && <button>🗑️ Удалить</button>}
      <button>👁️ Просмотреть</button>
    </div>
  )
}

Разрешения для полей форм

import { Protected } from 'rbac-react-system'

function UserForm() {
  return (
    <form>
      <input name="name" placeholder="Имя" />
      <input name="email" placeholder="Email" />

      <Protected resource="users" action="change-role">
        <select name="role">
          <option value="user">Пользователь</option>
          <option value="editor">Редактор</option>
          <option value="admin">Администратор</option>
        </select>
      </Protected>

      <Protected resource="users" action="change-status">
        <select name="status">
          <option value="active">Активный</option>
          <option value="blocked">Заблокирован</option>
        </select>
      </Protected>

      <button type="submit">Сохранить</button>
    </form>
  )
}

Матрица разрешений

function PermissionMatrix() {
  const { canAccess } = useRbac()
  const [matrix, setMatrix] = useState({})

  useEffect(() => {
    const checkPermissions = async () => {
      const result = {}
      const resources = ['posts', 'users', 'settings']
      const actions = ['read', 'write', 'delete']

      for (const resource of resources) {
        result[resource] = {}
        for (const action of actions) {
          result[resource][action] = await canAccess(resource, action)
        }
      }
      setMatrix(result)
    }

    checkPermissions()
  }, [canAccess])

  return (
    <table>
      <thead>
        <tr>
          <th>Ресурс</th>
          <th>Read</th>
          <th>Write</th>
          <th>Delete</th>
        </tr>
      </thead>
      <tbody>
        {Object.entries(matrix).map(([resource, actions]) => (
          <tr key={resource}>
            <td>{resource}</td>
            <td>{actions.read ? '✅' : '❌'}</td>
            <td>{actions.write ? '✅' : '❌'}</td>
            <td>{actions.delete ? '✅' : '❌'}</td>
          </tr>
        ))}
      </tbody>
    </table>
  )
}

📂 Папка примеров

В папке examples/ находятся подробные примеры для каждого сценария:

  1. 1-basic-setup.tsx - Базовая настройка ⭐

    • Создание провайдера
    • Mock репозитории
    • Базовая структура данных
  2. 2-hooks-usage.tsx - Использование хуков ⭐⭐

    • useRbac(), usePermission(), useAccess(), useRole()
    • Примеры для каждого хука
  3. 3-hoc-and-protected.tsx - HOC и компоненты ⭐⭐

    • withPermission, withRole
    • Protected компонент
    • Комбинированные примеры
  4. 4-advanced-scenarios.tsx - Продвинутые сценарии ⭐⭐⭐

    • Условия доступа (Conditions)
    • Иерархия ролей
    • Динамическое переключение пользователей
  5. 5-api-integration.tsx - REST API интеграция ⭐⭐⭐

    • Custom репозитории
    • Кэширование
    • Retry логика
    • Обработка ошибок
  6. 6-testing-examples.ts - Тестирование ⭐⭐⭐

    • Unit тесты
    • Integration тесты
    • Mock setup
  7. 7-error-handling.tsx - Обработка ошибок ⭐⭐

    • Error Boundary
    • Graceful degradation
    • Error logger

📖 Полное руководство по примерам: examples/README.md

📑 Полный индекс примеров: examples/INDEX.md

💻 TypeScript поддержка

Библиотека полностью типизирована:

import type {
  User,
  Role,
  Permission,
  Condition,
  IUserRepository,
  IRoleRepository,
  IPermissionRepository,
  RbacConfig,
  RbacContextValue
} from 'rbac-react-system'

⚡ Производительность

  • Мемоизация - Все хуки используют React memoization
  • Ленивая загрузка - Разрешения загружаются по требованию
  • Минимальные перерисовки - Обновления контекста оптимизированы
  • Tree Shaking - Импортируйте только то, что нужно

🌍 Поддерживаемые браузеры

  • Chrome (последняя версия)
  • Firefox (последняя версия)
  • Safari (последняя версия)
  • Edge (последняя версия)

🧪 Локальное тестирование

Хотите протестировать библиотеку в своем проекте БЕЗ публикации в npm?

Самый быстрый способ:

# В библиотеке
npm run pack:local

# В вашем проекте
npm install /path/to/rbac-react-system/rbac-react-system-1.0.4.tgz

Для активной разработки (рекомендуется):

# Установите yalc (один раз)
npm install -g yalc

# В библиотеке
npm run yalc:setup

# В вашем проекте
yalc add rbac-react-system

# При изменениях - автоматическое обновление
npm run dev:watch

🤝 Вклад в проект

Мы приветствуем вклад в проект!

Для разработчиков:

  • 📖 CONTRIBUTING.md - Полное руководство для разработчиков
  • DEVELOPMENT.md - Быстрый старт для разработки
  • 🧪 LOCAL_TESTING.md - Локальное тестирование

Процесс:

  1. Fork проекта
  2. Создайте ветку (git checkout -b feature/amazing-feature)
  3. Внесите изменения и добавьте тесты
  4. Убедитесь, что тесты проходят (npm test)
  5. Закоммитьте (git commit -m 'feat: add amazing feature')
  6. Push в ветку (git push origin feature/amazing-feature)
  7. Создайте Pull Request

📄 Лицензия

MIT © TM Project

🔗 Ссылки

📚 Дополнительная документация

❓ FAQ

Q: С какого примера начать? A: Начните с 1-basic-setup.tsx для понимания базовой конфигурации.

Q: Как интегрировать с REST API? A: Смотрите 5-api-integration.tsx для примера custom репозиториев.

Q: Как написать тесты? A: Используйте 6-testing-examples.ts как шаблон.

Q: Поддерживается ли наследование ролей? A: Да! Смотрите 4-advanced-scenarios.tsx для примеров.

Q: Как обновить разрешения пользователя? A: Вызовите refreshPermissions() из хука useRbac().


Спасибо за использование rbac-react-system! 🎉