Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript error on passing condition argument #990

Open
vholik opened this issue Nov 22, 2024 · 3 comments
Open

Typescript error on passing condition argument #990

vholik opened this issue Nov 22, 2024 · 3 comments
Labels

Comments

@vholik
Copy link

vholik commented Nov 22, 2024

Describe the bug

I'm using this guide to setup rbac in my application https://casl.js.org/v6/en/cookbook/roles-with-static-permissions.

Here is my final code:

import {
  createMongoAbility,
  ForcedSubject,
  CreateAbility,
  MongoAbility,
  AbilityBuilder
} from '@casl/ability'
import { MedusaError } from '@medusajs/framework/utils'
import { MemberDTO, MemberRole } from 'src/modules/seller/types'

export const actions = ['manage', 'read', 'create', 'update', 'delete'] as const
export const subjects = [
  'Invite',
  'Member',
  'Seller',
  'Product',
  'all'
] as const

type AppAbilities = [
  (typeof actions)[number],
  (
    | (typeof subjects)[number]
    | ForcedSubject<Exclude<(typeof subjects)[number], 'all'>>
  )
]

export type AppAbility = MongoAbility<AppAbilities>
export const createAppAbility = createMongoAbility as CreateAbility<AppAbility>

type DefinePermissions = (
  member: MemberDTO,
  builder: AbilityBuilder<AppAbility>
) => void

type Roles = MemberRole

const rolePermissions: Record<Roles, DefinePermissions> = {
  [MemberRole.OWNER]: (member, { can }) => {
    can('manage', 'all')
  },
  [MemberRole.ADMIN]: (member, { can }) => {
    can('manage', 'all')
  },
  [MemberRole.MODERATOR]: (member, { can }) => {
    can('read', 'Product')
    can('read', 'Invite')
    can('read', 'Seller')
    can('read', 'Member')
    can('update', 'Member', { id: member.id })
  }
}

export function defineAbilityFor(member: MemberDTO) {
  const builder = new AbilityBuilder(createAppAbility)

  if (typeof rolePermissions[member.role] === 'function') {
    rolePermissions[member.role](member, builder)
  } else {
    throw new MedusaError(
      MedusaError.Types.UNEXPECTED_STATE,
      `Trying to use unknown role "${member.role}"`
    )
  }

  return builder.build()
}

But I get this typescript error that I can not pass id in here

can('update', 'Member', { id: member.id })
image

Changing syntax to mongo query does not help.

Expected behavior
I should not get any typescript error

@vholik vholik added the bug label Nov 22, 2024
@stalniy
Copy link
Owner

stalniy commented Nov 22, 2024

could you please point me to the line where you tell casl the shape of Member subject type?

@stalniy stalniy added question and removed bug labels Nov 22, 2024
@vholik
Copy link
Author

vholik commented Nov 22, 2024

@stalniy are you refering to the fact that I should pass DTO types together with the subject strings?

export type Action = 'manage' | 'read' | 'create' | 'update' | 'delete'
export type Subject =
  | 'Invite'
  | 'Member'
  | 'Seller'
  | 'Product'
  | 'all'
  | MemberDTO
  | MemberInviteDTO
  | SellerDTO
  | ProductDTO

@stalniy
Copy link
Owner

stalniy commented Nov 22, 2024

Yes and DTO should be connected with subject type.

You can read about it here - https://casl.js.org/v6/en/advanced/typescript#infer-subject-types-from-interfaces-and-classes

The thing is that you need to wrap your DTOs with ForcedSubject<T> only if your DTOs do not know their type names (just simple POJOs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants