or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

advanced-utilities.mdcore-abilities.mderror-handling.mdindex.mdpermission-checking.mdrule-building.md
tile.json

tessl/npm-casl--ability

Isomorphic authorization JavaScript library which restricts what resources a given user is allowed to access

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@casl/ability@6.7.x

To install, run

npx @tessl/cli install tessl/npm-casl--ability@6.7.0

index.mddocs/

CASL Ability

CASL (pronounced "castle") is an isomorphic authorization JavaScript library that enables fine-grained access control through a declarative rule-based approach. It supports both simple claim-based authorization and complex subject and attribute-based authorization (ABAC), providing a fluent API for defining permissions with MongoDB-style query operators.

Package Information

  • Package Name: @casl/ability
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @casl/ability

Core Imports

import { 
  createMongoAbility, 
  defineAbility, 
  AbilityBuilder, 
  PureAbility,
  ForbiddenError,
  subject,
  detectSubjectType,
  createAliasResolver,
  wrapArray,
  mongoQueryMatcher,
  fieldPatternMatcher
} from "@casl/ability";

// Type imports
import type {
  AnyMongoAbility,
  MongoAbility,
  AbilityTuple,
  Subject,
  SubjectType,
  Abilities,
  ForcedSubject,
  CanParameters
} from "@casl/ability";

// HKT namespace import
import * as hkt from "@casl/ability/hkt";

For CommonJS:

const { 
  createMongoAbility, 
  defineAbility, 
  AbilityBuilder, 
  PureAbility,
  ForbiddenError,
  subject,
  detectSubjectType,
  createAliasResolver,
  wrapArray,
  mongoQueryMatcher,
  fieldPatternMatcher
} = require("@casl/ability");

Basic Usage

import { createMongoAbility, defineAbility, AbilityBuilder } from "@casl/ability";

// Method 1: Factory function with rules array
const ability = createMongoAbility([
  { action: 'read', subject: 'Post' },
  { action: 'create', subject: 'Post', conditions: { authorId: '${user.id}' } },
  { action: 'delete', subject: 'Post', inverted: true, conditions: { published: true } }
]);

// Method 2: Functional DSL
const ability2 = defineAbility((can, cannot) => {
  can('read', 'Post');
  can('create', 'Post');
  cannot('delete', 'Post', { published: true });
});

// Method 3: Builder pattern
const { can, cannot, build } = new AbilityBuilder(createMongoAbility);
can('read', 'Post');
can('update', 'Post', { authorId: 'user123' });
cannot('delete', 'Post', { published: true });
const ability3 = build();

// Check permissions
if (ability.can('read', 'Post')) {
  console.log('Can read posts');
}

if (ability.cannot('delete', { __type: 'Post', published: true })) {
  console.log('Cannot delete published posts');
}

Architecture

CASL is built around several key components:

  • Core Classes: PureAbility (base class) and specialized ability classes for different use cases
  • Rule System: Declarative rules with actions, subjects, conditions, and field restrictions
  • Matchers: Pluggable condition matching (MongoDB queries, custom matchers) and field pattern matching
  • Builder API: AbilityBuilder for fluent rule construction and defineAbility functional DSL
  • Error Handling: ForbiddenError with detailed context for permission violations
  • Type System: Full TypeScript support with generic constraints and type inference

Capabilities

Core Ability Management

Create and manage ability instances with rule-based permissions. The foundation for all authorization logic.

function createMongoAbility<T = AnyMongoAbility>(
  rules?: RawRuleOf<T>[],
  options?: AbilityOptionsOf<T>
): T;

function defineAbility<T = AnyMongoAbility>(
  define: (can: DefineRule<T>, cannot: DefineRule<T>) => void | Promise<void>,
  options?: AbilityOptionsOf<T>
): T | Promise<T>;

class PureAbility<A extends Abilities = Abilities, Conditions = AnyObject> {
  can(...args: CanParameters<A>): boolean;
  cannot(...args: CanParameters<A>): boolean;
  relevantRuleFor(...args: CanParameters<A>): Rule<A, Conditions> | null;
  update(rules: RawRuleFrom<A, Conditions>[]): this;
}

Core Ability Management

Permission Checking

Check permissions against subjects with optional conditions and field-level access control.

type CanParameters<A extends Abilities> = 
  | [action: A, subject?: Subject]
  | [action: A, subject: Subject, field?: string];

interface Rule<A extends Abilities, Conditions> {
  readonly action: string | string[];
  readonly subject?: string | string[];
  readonly conditions?: Conditions;
  readonly fields?: string[];
  readonly inverted: boolean;
  readonly reason?: string;
  matchesConditions(object: any): boolean;
  matchesField(field: string): boolean;
}

Permission Checking

Fluent Rule Building

Build complex permission rules using fluent builder pattern or functional DSL approach.

class AbilityBuilder<T extends AnyAbility> {
  rules: RawRuleOf<T>[];
  can: DefineRule<T>;
  cannot: DefineRule<T>;
  build(options?: AbilityOptionsOf<T>): T;
}

type DefineRule<T extends AnyAbility> = (
  action: Parameters<T['can']>[0],
  subject?: Parameters<T['can']>[1],
  conditionsOrFields?: any,
  fields?: string | string[]
) => void;

Fluent Rule Building

Error Handling

Handle permission violations with detailed error context and customizable messages.

class ForbiddenError<T extends AnyAbility = AnyAbility> extends Error {
  readonly ability: T;
  readonly action: string;
  readonly subject: any;
  readonly field?: string;
  readonly subjectType: string;

  static setDefaultMessage(messageOrFn: string | ErrorMessageFactory): void;
  static from<U extends AnyAbility>(ability: U): ForbiddenError<U>;
  
  setMessage(message: string): this;
  throwUnlessCan(...args: Parameters<T['can']>): void;
  unlessCan(...args: Parameters<T['can']>): this | undefined;
}

Error Handling

Advanced Utilities

Advanced features for serialization, database integration, and field-level access analysis.

// Rule serialization (from @casl/ability/extra)
function packRules<T extends RawRule<any, any>>(
  rules: T[], 
  packSubject?: (subject: any) => any
): PackRule<T>[];

function unpackRules<T extends RawRule<any, any>>(
  rules: PackRule<T>[], 
  unpackSubject?: (subject: any) => any
): T[];

// Field analysis
function permittedFieldsOf<T extends AnyAbility>(
  ability: T,
  action: Parameters<T['can']>[0],
  subject: Parameters<T['can']>[1],
  options?: { fieldsFrom?: any }
): string[];

// Query generation
function rulesToQuery<T extends AnyAbility, Q>(
  ability: T,
  action: Parameters<T['can']>[0],
  subjectType: string,
  convert: (rule: Rule<any, any>) => Q
): Q | null;

Advanced Utilities

Utility Functions

Core utility functions for subject type handling, array processing, and alias management.

/**
 * Set subject type on object for explicit type detection
 * @param type - Subject type name to set
 * @param object - Object to tag with subject type
 * @returns Tagged object with forced subject type
 */
function subject<T extends string, U extends Record<PropertyKey, any>>(
  type: T, 
  object: U
): U & ForcedSubject<T>;

/**
 * Detect subject type from object instance
 * @param object - Object to detect type from
 * @returns String representation of subject type
 */
function detectSubjectType(object: Exclude<Subject, SubjectType>): string;

/**
 * Create action alias resolver for expanding action shortcuts
 * @param aliasMap - Map of aliases to action arrays
 * @param options - Optional configuration
 * @returns Function that expands aliases to full action arrays
 */
function createAliasResolver(
  aliasMap: AliasesMap, 
  options?: AliasResolverOptions
): (action: string | string[]) => string[];

/**
 * Wrap value in array if not already an array
 * @param value - Value to wrap
 * @returns Array containing the value
 */
function wrapArray<T>(value: T[] | T): T[];

// Matcher functions
function mongoQueryMatcher<T = AnyObject>(conditions: MongoQuery<T>): MatchConditions<T>;
function fieldPatternMatcher(fields: string[]): MatchField<string>;

// Support types
interface AliasResolverOptions {
  skipValidate?: boolean;
  anyAction?: string;
}

Core Types

// Basic utility types
type AnyClass<ReturnType = any> = new (...args: any[]) => ReturnType;
type AnyObject = Record<PropertyKey, unknown>;
type AnyRecord = Record<PropertyKey, any>;

// Subject and ability types
type SubjectClass<N extends string = string> = AnyClass & { modelName?: N };
type SubjectType = string | SubjectClass;
type Subject = AnyRecord | SubjectType;
type AbilityTuple<X extends string = string, Y extends Subject = Subject> = [X, Y];
type Abilities = AbilityTuple | string;

// Rule definition types
interface RawRule<A extends Abilities, C = AnyObject> {
  action: A extends readonly [infer Action, any] ? Action : A;
  subject?: A extends readonly [any, infer S] ? S : string;
  conditions?: C;
  fields?: string | string[];
  inverted?: boolean;
  reason?: string;
}

// Type utilities
type Normalize<T extends Abilities> = T extends AbilityTuple ? T : [T, string];
type IfString<T, U> = T extends string ? U : never;

// Tagged interface support
interface ForcedSubject<T> {
  readonly __caslSubjectType__: T;
}

type TaggedInterface<T extends string> = ForcedSubject<T> |
  { readonly kind: T } |
  { readonly __typename: T };

type TagName<T> = T extends TaggedInterface<infer U> ? U : never;
type ExtractSubjectType<S extends Subject> = Extract<S, SubjectType> | TagName<S>;

type SubjectClassWithCustomName<T> = AnyClass & { modelName: T };
type InferSubjects<T, IncludeTagName extends boolean = false> =
  T | (T extends AnyClass<infer I>
    ? I | (IncludeTagName extends true
      ? T extends SubjectClassWithCustomName<infer Name> ? Name : TagName<I>
      : never)
    : TagName<T>);

// Parameter types
type Fn = (...args: any[]) => any;
type AbilityParameters<
  T extends Abilities,
  TupleFunction extends Fn,
  StringFunction extends Fn = () => 0,
  Else = IfString<T, Parameters<StringFunction>>
> = T extends AbilityTuple ? Parameters<TupleFunction> : Else;

type CanParameters<T extends Abilities, IncludeField extends boolean = true> =
  AbilityParameters<
    T,
    T extends AbilityTuple
      ? IncludeField extends true
        ? (action: T[0], subject: T[1], field?: string) => 0
        : (action: T[0], subject: T[1]) => 0
      : never,
    (action: Extract<T, string>) => 0
  >;

// MongoDB integration types
type MongoQuery<T = AnyObject> = Record<string, any>;
type MongoAbility<
  A extends AbilityTuple = AbilityTuple, 
  C extends MongoQuery = MongoQuery
> = PureAbility<A, C>;
type AnyMongoAbility = MongoAbility<any, any>;

// Matcher types
type MatchConditions<T extends {} = AnyRecord> = {
  (object: T): boolean;
  ast?: any; // Condition type from @ucast/mongo2js
};
type ConditionsMatcher<T> = (conditions: T) => MatchConditions;
type MatchField<T extends string> = (field: T) => boolean;
type FieldMatcher = <T extends string>(fields: T[]) => MatchField<T>;

// Rule index and event types (exported from main module)
interface Generics<T> {
  abilities: any;
  conditions: any;
}

type RawRuleOf<T extends AnyAbility> = RawRule<Generics<T>['abilities'], Generics<T>['conditions']>;
type RuleOf<T extends AnyAbility> = Rule<Generics<T>['abilities'], Generics<T>['conditions']>;

interface UpdateEvent<T extends AnyAbility> {
  rules: RawRuleOf<T>[];
}
type EventHandler<T> = (event: T) => void;
type Unsubscribe = () => void;

// Utility types
type AliasesMap = Record<string, string | string[]>;