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') // trueIt 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.