Skip to content
On this page

@semantic-api/access-control

Types

Global API

Role

ts
export type Role<
  TCollections extends Record<string, CollectionStructure>,
  TAlgorithms extends Record<string, AlgorithmStructure>,
  TAccessControl extends AccessControl<TCollections, TAlgorithms>=any
> = {
  inherit?: Array<keyof TAccessControl['roles'] | keyof typeof baseRoles>
  grantEverything?: boolean
  forbidEverything?: boolean
  capabilities?: {
    [P in keyof (TCollections & TAlgorithms)]?: {
      grantEverything?: boolean
      forbidEverything?: boolean
      functions?: 'functions' extends keyof (TCollections & TAlgorithms)[P]
        ? Array<keyof (TCollections & TAlgorithms)[P]['functions']>
        : never
      blacklist?: 'functions' extends keyof (TCollections & TAlgorithms)[P]
        ? Array<keyof (TCollections & TAlgorithms)[P]['functions']>
        : never
    }
  }
}

AccessControl

ts
export type InternalAccessControl<
  TCollections extends Record<string, CollectionStructure>,
  TAlgorithms extends Record<string, AlgorithmStructure>,
  TAccessControl extends AccessControl<TCollections, TAlgorithms>=any
> = {
  roles?: Roles<TCollections, TAlgorithms, TAccessControl>
  availableRoles?: keyof TAccessControl['roles']
  parent?: TAccessControl['roles']
}

export type AccessControl<
  TCollections extends Record<string, CollectionStructure>,
  TAlgorithms extends Record<string, AlgorithmStructure>,
  TAccessControl extends AccessControl<TCollections, TAlgorithms>=any
> = InternalAccessControl<TCollections, TAlgorithms, TAccessControl> & {
  layers?: Partial<Record<ValidAccessControlLayer, AccessControlLayer<TCollections, TAlgorithms, TAccessControl>>>
}

AccessControlLayer

ts
export type AccessControlLayerProps<TPayload extends Record<string, any>=any> = {
  propertyName?: string
  parentId?: string
  childId?: string
  payload: TPayload
}

export type AccessControlLayer<
  TCollections extends Record<string, CollectionStructure>,
  TAlgorithms extends Record<string, Awaited<ReturnType<Algorithm>>>,
  TAccessControl extends AccessControl<TCollections, TAlgorithms>=any
> = (context: Context<any, TCollections, TAlgorithms, TAccessControl>, props: AccessControlLayerProps) => Promise<Either<
  ACErrors,
  ReadPayload | WritePayload
>>

ValidAccessControlLayer

ts
export type ValidAccessControlLayer =
  'read'
  | 'write'
  | 'call'

defineAccessControl

Defines a AccessControl object while providing strong typing.

ts
export const defineAccessControl = <
  TCollections extends Record<string, CollectionStructure>,
  TAlgorithms extends Record<string, AlgorithmStructure>,
>() => <const TAccessControl extends AccessControl<TCollections, TAlgorithms, TAccessControl>>(accessControl: TAccessControl) =>
  (layers?: Partial<Record<ValidAccessControlLayer, AccessControlLayer<TCollections, TAlgorithms, TAccessControl>>>) => {
  const roles = {}
  Object.assign(roles, baseRoles)
  Object.assign(roles, accessControl.roles)

  accessControl.roles = roles
  accessControl.layers = layers
  return accessControl
}

Example

typescript
import { defineAccessControl } from '@semantic-api/access-control'

export const accessControl = defineAccessControl<Collections, Algorithms>()({
  roles: {
    guest: {
      inherit: [
        'unauthenticated',
        // will produce TS diagnostics since there's no 'non_existent' role to inherit
        // 'non_existent'
      ],
      capabilities: {
        someResource: {
          grantEverything: true
        }
      }
    }
  }
})({
  read: async (context, { payload }) => {
    // will produce TS diagnostics since 'non_existent' role wasn't provided
    // if( context.token.user.roles.includes('non_existent') ) {
    //   context.log('oh no!')
    // }
  }
})

Last updated: