A flexible, type-safe JavaScript library for authorization and permission checking. Define rules with a composable builder DSL, check permissions against resource instances, and leverage context-aware conditions — all with full TypeScript support.
# ✨ Auto-detect
npx nypm install guantr
# npm
npm install guantr
# yarn
yarn add guantr
# pnpm
pnpm add guantr
# bun
bun install guantr
# deno
deno install npm:guantrESM (Node.js, Bun, Deno)
import { createGuantr } from 'guantr';CommonJS (Legacy Node.js)
const { createGuantr } = require('guantr');CDN (Deno and Browsers)
import { createGuantr } from 'https://esm.sh/guantr';import { createGuantr } from 'guantr';
import type { GuantrMeta } from 'guantr';
// 1. Define your resource map and context
type MyMeta = GuantrMeta<
{
post: {
action: 'read' | 'create' | 'update' | 'delete';
model: { id: number; title: string; published: boolean; authorId: number };
};
},
{ userId: number }
>;
// 2. Create an instance
const guantr = await createGuantr<MyMeta>({
context: () => ({ userId: 1 }),
});
// 3. Set rules with the builder DSL
await guantr.setRules((allow, deny) => {
allow('read', 'post');
deny('read', ['post', ({ eq, resource, literal }) => eq(resource('published'), literal(false))]);
allow('update', [
'post',
({ eq, resource, context }) => eq(resource('authorId'), context('userId')),
]);
});
// 4. Check permissions
const post = { id: 1, title: 'Hello', published: false, authorId: 1 };
await guantr.can.abstract('read', 'post'); // true — any allow rule exists?
await guantr.can('read', ['post', post]); // false — denied by condition
await guantr.can('update', ['post', post]); // true — author is owner
// Batch checks — context resolved once
await guantr.can.all([
['read', ['post', post]],
['update', ['post', post]],
]);Guantr v2 uses a type-safe builder DSL for conditions:
import type { MatchConditionFn } from 'guantr';
const condition: MatchConditionFn<Post, Context> = ({ and, eq, resource, literal }) =>
and(eq(resource('status'), literal('published')), eq(resource('deleted'), literal(false)));
// Use in rule objects or callbacks:
await guantr.setRules([
{
effect: 'allow',
action: 'read',
resource: 'post',
matchCondition: condition,
},
]);All conditions are serialized to a JSON-compatible AST at definition time, making them storable in any database.
| Method | Description |
|---|---|
can(action, [resourceKey, instance]) |
Full evaluation against a specific instance |
cannot(action, [resourceKey, instance]) |
Negated can |
can.abstract(action, resourceKey) |
Any allow rule exists? (ignores conditions/denies) |
cannot.abstract(action, resourceKey) |
Negated can.abstract |
can.all(checks) |
All checks must pass |
can.any(checks) |
Any check must pass |
cannot.all(checks) |
All checks must be denied |
cannot.any(checks) |
Any check must be denied |
| Method | Description |
|---|---|
setRules((allow, deny) => {}) |
Replace rules via callback |
setRules([...]) |
Replace rules via array |
getRules() |
Retrieve all stored rules |
relatedRulesFor(action, resource) |
Query rules by action + resource |
await createGuantr<Meta>({
context: () => ({ userId: 1 }), // default: {}
storage: new MyCustomStorage(), // default: InMemoryStorage
maxRuleIterations: 500, // default: 1000
});local development
Published under the MIT license.
Made by community 💛
🤖 auto updated with automd