Charter · guide

Resolve a role

A role, a list of what exists, and the names that role selects. One wildcard, and a deny that wins.

Install it
pnpm add @niscorp/charter
Step 1 of 5

What exists

Charter is always handed the list of what exists. Here it is the ids of the screens the theatre’s app ships. An id with a dot in it, like me.tickets, is just a name: the dot is there so one pattern can select a family.

What exists
import { resolvePrincipal } from '@niscorp/charter';

const screens = [
  'welcome',
  'programme',
  'seats',
  'me.tickets',
  'me.pass',
  'door.list',
  'members',
  'takings',
  'settings',
];
Step 2 of 5

A role is a list of patterns

A charter is an object of roles. The shortest role is a list of patterns over the names that exist.

A plain name selects itself. * matches any run of characters, dots included, so me.* is every screen whose id starts with me.. There is no other pattern.

A role is a list of patterns
const charter = {
  guest: ['welcome', 'programme'],
  member: ['programme', 'seats', 'me.*'],
};
Step 3 of 5

Resolve it

resolvePrincipal takes the charter, the list of what exists, and the roles a person has. It answers with the set of names those roles select. Nothing outside the set is granted: what no role mentions is denied.

Resolve it
console.log('member:', [...resolvePrincipal(charter, screens, ['member'])]);
console.log('guest:', [...resolvePrincipal(charter, screens, ['guest'])]);
Step 4 of 5

Allow, then deny

A role can also be written as what it allows and what it denies. This one allows every screen and takes four back.

A deny wins over an allow in the same role, whatever order they are written in.

Allow, then deny
const withStaff = {
  ...charter,
  staff: { allow: ['*'], deny: ['welcome', 'me.*', 'settings'] },
};
console.log('staff:', [...resolvePrincipal(withStaff, screens, ['staff'])]);
Step 5 of 5

Two roles on one person

A person with two roles has what either role selects. Roles add up. A deny in one role does not take away what another role gives.

Two roles on one person
console.log('member and staff:', [...resolvePrincipal(withStaff, screens, ['member', 'staff'])].length, 'screens');
Then

Run it.

The four screens a member has, the two a guest has, the five staff have once the denies are taken out, and how many somebody with both roles has.

Run it
npx tsx resolve.mts
It prints
member: [ 'programme', 'seats', 'me.tickets', 'me.pass' ]
guest: [ 'welcome', 'programme' ]
staff: [ 'programme', 'seats', 'door.list', 'members', 'takings' ]
member and staff: 7 screens