casl-prisma-generator generates CASL subjects from schema.prisma file
npm install casl-prisma-generator
# or
yarn add casl-prisma-generator
# or
pnpm add casl-prisma-generator
In package.json
add:
"casl-generate": "npx ts-node ./src/casl/generator.ts",
"prisma:generate": "prisma generate && npm run casl-generate",
enum UserType {
ADMIN
USER
}
model User {
id String @id @default(uuid())
type UserType @default(USER)
password String
}
model Post {
id String @id @default(uuid())
content String @db.VarChar(2048)
}
model Item {
id String @id @default(uuid())
}
model Subject {
id String @id @default(uuid())
}
import { generateCaslSubjectsToFile } from 'casl-prisma-generator/dist';
generateCaslSubjectsToFile('src/casl/generated/subjectsList.ts');
The result will be: src/casl/generated/subjectsList.ts
:
/** this file is auto generated, don't touch it **/
import { User, Post, Item, Subject } from '@prisma/client';
export type SubjectsList = {
User: User;
Post: Post;
Item: Item;
Subject: Subject;
};
import {
generateCaslSubjectsToFile,
OverrideSubjects,
} from 'casl-prisma-generator/dist';
const overrides: OverrideSubjects = {
User: {
typeName: 'JwtUser',
importPath: "import { JwtUser } from 'src/auth/types-auth';",
},
Post: null,
};
generateCaslSubjectsToFile('src/casl/generated/subjectsList.ts', overrides, {
prismaSchemaPath: 'prisma/schema.prisma',
prismaClientPath: '@prisma/client',
});
The result will be: src/casl/generated/subjectsList.ts
:
/** this file is auto generated, don't touch it **/
import { Item, Subject } from '@prisma/client';
import { JwtUser } from 'src/auth/types-auth';
export type SubjectsList = {
User: JwtUser;
Item: Item;
Subject: Subject;
};
Notice: User: JwtUser;
and we removed Post: Post;
import { AbilityBuilder, PureAbility } from '@casl/ability';
import { Subjects } from '@casl/prisma';
import { PrismaQuery, createPrismaAbility } from '@casl/prisma';
import { JwtUser } from 'src/auth/types-auth';
import { SubjectsList } from 'src/casl/generated/subjectsList';
export type Action = 'manage' | 'create' | 'read' | 'update' | 'delete';
export type AppAbility = PureAbility<
[Action, Subjects<SubjectsList> | 'all'],
PrismaQuery
>;
export function createForUser(user: JwtUser) {
const { can, cannot, build } = new AbilityBuilder<AppAbility>(
createPrismaAbility,
);
if (user.type === 'ADMIN') {
can('manage', 'all'); // read-write access to everything
} else {
can('manage', 'User', { id: user.id });
}
return build();
}
nest-prisma-casl-starter: this project implements CASL and Prisma with NestJs