Skip to content

Channels

One of the biggest advantages of feathers-casl is the built in support for channels. If you're not familiar with channels, please read the official feathers.js docs. This chapter is only relevant for you, if you're using realtime connections (most likely socket.io). You can't use channels, if you've 'only' a REST app by using express.js or koa.

Example

ts
// src/channels.ts
import { getChannelsWithReadAbility, makeChannelOptions } from "feathers-casl";

export default function (app) {
  if (typeof app.channel !== "function") {
    // If no real-time functionality has been configured just return
    return;
  }

  // ...

  app.on("login", (authResult: any, { connection }) => {
    if (connection) {
      // this is needed to map the ability from the authentication hook to the connection so it gets available in the HookContext as `params.ability` automatically
      if (authResult.ability) {
        connection.ability = authResult.ability;
        connection.rules = authResult.rules;
      }

      // ...
    }

    // ...
  });

  // ...

  const caslOptions = makeChannelOptions(app);

  app.publish((data, context) => {
    return getChannelsWithReadAbility(app, data, context, caslOptions);
  });
}

makeOptions

Properties:

  • app: Application: required - used because of app.configure(casl())
  • options: Partial<ChannelOptions>: optional - see the table below.

returns ChannelOptions

Options

PropertyDescription
abilityYou can define a custom ability. If it's not defined, feathers-casl looks for connection.ability by default which exists, if you followed the Getting Started instructions. If it doesn't find an ability, the connection will not be informed.


Type: Ability ((app: Application, connection: RealTimeConnection, data: any, context: HookContext) => Ability)
optional - Default: (app, connection) => connection.ability
activatedDeactivating the feathers-casl channels functionality is as easy as set this to false. It will return your channelOnError then.

Type: boolean
optional - Default: true
availableFieldsCaution! This is needed for @casl/ability starting with v5!

If you have rules with restricted fields, you want to provide a full list of possibly occurring fields for this service. If it's undefined (by default) feathers-casl cannot distinguish wether an empty set of restricted fields comes from restrictions or from the missing declaration. For standard adapters, you'll find the according function in the cookbook.

Type: string[] | ((context: HookContext) => string[])
Default: looks at options.casl.availableFields of the service, otherwise undefined
channelOnErrorIf you set activated:false or your custom 'modelName' returns nothing, the channelOnError will be returned.

Type: string[]
Default: ['authenticated']
channelsgetChannelsWithReadAbility by default filters from all existing connections. With the option channels you can pass prefiltered channels. So only the connections of the channel / these channels will be considered. You want to use this in a specific service.publish function where you want to return a specific channel (e.g. app.channel(`room-${roomId})) and want to filter that afterwards.

Type: Channel | Channel[]
optional - Default: app.channel(app.channels)
modelNamefeathers-casl checks permissions per item. Because most items are plain javascript objects, it does not know which type the item is. Per default it looks for context.path (for example: tasks). You can change this behaviour with the option 'modelName' to use Class-like names (for example: Task)

Type: string or ((context: HookContext) => string)
optional - Default: (context) => context.path
restrictFieldsThis is one of the most outstanding things of feathers-casl. If you define rules like: can('read', 'posts', ['id', 'title', 'body']) with restricting fields, it will be considered in the getChannelsWithReadAbility per each individual connection. If you wish, you can skip this behavior.

Type: boolean
optional - Default: true
useActionNamegetChannelsWithReadAbility by default uses your 'get' rules. So every connected device via socket.io receives events, if it has the appropriate 'get' rule defined. You maybe want to change who can 'get' items and who can 'receive' realtime updates. You can change 'useActionName' then to whatever string you like. For example: useActionName: 'receive' -> can('receive', 'posts'). That way you split the rules for events and for normal requests which is why you have to define all rules for events separately then. You even can change the action-name per event individually.

Type: string | { created: string, updated: string, patched: string, removed: string }
optional - Default: 'get'

getChannelsWithReadAbility

Properties:

  • app: Application: required - used for app.channel and app.channels under the hood
  • data: any: required - the data from the event
  • context: HookContext: required - used to get the servicePath/modelName under the hood
  • caslOptions?: Partial<ChannelOptions>: optional - see the table above returns Channel | Channel[]

Released under the MIT License.