Permix

Introduction

The type-safe permission management you've always needed

Idea

In my many years of experience, I have worked extensively with permissions management, and early in my career I wrote solutions that looked like this:

if (user.role === 'admin') {
  // do something
}

Later, I started using CASL for permissions management in a Vue application.

can('read', ['Post', 'Comment']);
can('manage', 'Post', { author: 'me' });
can('create', 'Comment');

But time goes on, CASL becomes older, and developers' needs grow, especially for type-safe libraries. Unfortunately, CASL couldn't satisfy my type validation needs and so I started thinking again about writing my own validation solution. But this time I wanted to make it as a library, as I already had experience with open-source.

Implementation

I started to create my own solution. However, nothing occurred to me until I watched a Web Dev Simplified video where he demonstrated an example of implementing permission management as he envisioned it. I really liked his approach because it was based on type-safety, which is exactly what I needed.

So I'm ready to present to you my permission management solution called Permix!

DX

When creating Permix, the goal was to simplify DX as much as possible without losing type-safety and provide the necessary functionality.

That is why you only need to write the following code to get started:

import {  } from 'permix'
 
const  = <{
  : {
    : 'read'
  }
}>()
 
.({
  : {
    : true,
  }
})
 
const  = .('post', 'read') // true

It looks too simple, so here's a more interesting example:

import type {  } from 'permix'
import {  } from 'permix'
 
// You can take types from your database
interface User {
  : string
  : 'editor' | 'user'
}
 
interface Post {
  : string
  : string
  : string
  : boolean
}
 
interface Comment {
  : string
  : string
  : string
}
 
// Create definition to describe your permissions
type  = <{
  : {
    : Post
    : 'create' | 'read' | 'update' | 'delete'
  }
  : {
    : Comment
    : 'create' | 'read' | 'update'
  }
}>
 
const  = <>()
 
// Define permissions for different users
const  = .({
  : {
    : true,
    : true,
    :  => !.,
    :  => !.,
  },
  : {
    : false,
    : true,
    : false,
  },
})
 
const  = .(({ :  }: User) => ({
  : {
    : false,
    : true,
    : false,
    : false,
  },
  : {
    : true,
    : true,
    :  => . === ,
  },
}))
 
async function () {
  // Imagine that this function is fetching user from database
  return {
    : '1',
    : 'editor' as ,
  }
}
 
// Setup permissions for signed in user
async function () {
  const  = await ()
  const  = {
    : () => (),
    : () => (),
  }
 
  .([.]())
}
 
// Call setupPermix where you need to setup permissions
()
 
// Check if a user has permission to do something
const  = .('post', 'create')
 
async function () {
  // Imagine that this function is fetching comment from database
  return {
    : '1',
    : 'Hello, world!',
    : '1',
  }
}
 
const  = await ()
 
const  = .('comment', 'update', )

Benefits

What are the benefits of using Permix?

  • 100% type-safe without writing TypeScript (except for initialization)
  • Single source of truth for your entire app
  • Perfect match for TypeScript monorepos
  • Zero dependencies
  • Useful methods for specific cases
  • Large number of integrations for different frameworks, such as React, Vue, Express, and more.

Ready?

Ready to take Permix to your project? Let's go to the Quick Start page.

On this page