gittech. site

for different kinds of informations and explorations.

Durin – A Permissions Guardian

Published at
19 hours ago

πŸšͺ Durin

Speak friend and enter: A lightweight TypeScript-based permissions guardian for React applications

npm version License: MIT TypeScript

Features

  • 🎯 Simple, lightweight role-based access control
  • πŸ”’ Type-safe permission management
  • βš›οΈ React-first design
  • πŸͺΆ Zero dependencies
  • πŸ“¦ Tree-shakeable
  • πŸ§ͺ Thoroughly tested

Installation

npm install @sparkforge/durin
# or
yarn add @sparkforge/durin
# or
pnpm add @sparkforge/durin

Quick Start

import { PermissionProvider, Protected, usePermissions } from 'durin';

// Define your roles and permissions
const roles = [
  {
    name: 'admin',
    permissions: ['create:users', 'edit:users', 'delete:users']
  },
  {
    name: 'editor',
    permissions: ['edit:users']
  }
];

// Wrap your app with the provider
function App() {
  const userRoles = ['editor']; // Get this from your auth system

  return (
    <PermissionProvider roles={roles} userRoles={userRoles}>
      <YourApp />
    </PermissionProvider>
  );
}

// Use the Protected component
function UserManagement() {
  return (
    <div>
      <Protected 
        requiredPermission="edit:users"
        fallback={<p>Access denied</p>}
      >
        <EditUserForm />
      </Protected>
    </div>
  );
}

// Or use the hook directly
function AdminPanel() {
  const { hasPermission, hasRole } = usePermissions();

  if (!hasRole('admin')) {
    return <p>Admin access required</p>;
  }

  return <div>Admin Panel Content</div>;
}

API Reference

PermissionProvider

The root provider component that manages permissions state.

Props

{
  roles: Array<{
    name: string;
    permissions: string[];
  }>;
  userRoles: string[];
  children: ReactNode;
}

Protected

A component wrapper that conditionally renders based on permissions.

Props

{
  requiredPermission?: string;
  requiredRole?: string;
  fallback?: ReactNode;
  children: ReactNode;
}

usePermissions

A hook for programmatically checking permissions.

const {
  hasPermission: (permission: string) => boolean,
  hasRole: (role: string) => boolean,
  userRoles: Array<{ name: string; permissions: string[] }>
} = usePermissions();

Best Practices

  1. Define Clear Permission Names

    • Use colon-separated format: resource:action
    • Example: users:create, posts:edit
  2. Role Hierarchies

    • Keep role structures flat when possible
    • Include all required permissions explicitly
  3. Error Handling

    • Always provide fallback content
    • Handle loading states appropriately
  4. Type Safety

    • Define permission and role types
    • Use string literals for better type inference

Examples

Nested Permissions

<Protected requiredPermission="users:edit">
  <div>
    <h1>User Settings</h1>
    <Protected requiredPermission="users:delete">
      <DeleteUserButton />
    </Protected>
  </div>
</Protected>

Combined Role and Permission Checks

<Protected 
  requiredRole="admin"
  requiredPermission="settings:edit"
>
  <AdminSettings />
</Protected>

Dynamic Permissions

function FeatureFlag({ feature, children }) {
  const { hasPermission } = usePermissions();
  return hasPermission(`feature:${feature}`) ? children : null;
}

Contributing

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create your feature branch
  3. Make your changes
  4. Run the tests (npm test)
  5. Submit a pull request

License

MIT Β© [SparkForge]


"Not all those who wander are lost, but some just don't have the right permissions." - Gandalf, probably