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.