@shield-acl/react
Version:
Sistema ACL (Access Control List) inteligente e granular para aplicações React
1 lines • 110 kB
Source Map (JSON)
{"version":3,"sources":["../src/context.tsx","../src/hooks/useACL.ts","../src/hooks/useCan.ts","../src/hooks/useCanAny.ts","../src/hooks/useCanAll.ts","../src/hooks/usePermissionHelpers.ts","../src/hooks/usePermissions.ts","../src/hooks/useCanMultiple.ts","../src/hooks/useResourceACL.ts","../src/hooks/usePermissionState.ts","../src/hooks/useConditionalPermissions.ts","../src/hooks/useEvaluate.ts","../src/hooks/useRoleHierarchy.ts","../src/hooks/usePermissionChange.ts","../src/components.tsx"],"sourcesContent":["import {\n createContext,\n useContext,\n useState,\n useCallback,\n useMemo,\n} from \"react\";\nimport type {\n ACLEngine,\n EvaluationResult,\n PermissionAction,\n ResourceType,\n User,\n} from \"@shield-acl/core\";\n\n/**\n * Valor do contexto ACL\n */\nexport interface ACLContextValue<TContext = any> {\n engine: ACLEngine<TContext>;\n user: User<TContext> | null;\n setUser: (user: User<TContext> | null) => void;\n can: (\n action: PermissionAction,\n resource?: ResourceType,\n context?: TContext,\n ) => boolean;\n evaluate: (\n action: PermissionAction,\n resource?: ResourceType,\n context?: TContext,\n ) => EvaluationResult;\n}\n\n/**\n * Context do ACL\n */\nconst ACLContext = createContext<ACLContextValue | undefined>(undefined);\n\n/**\n * Props do Provider\n */\nexport interface ACLProviderProps<TContext = any> {\n engine: ACLEngine<TContext>;\n user?: User<TContext> | null;\n children: React.ReactNode;\n}\n\n/**\n * Provider do ACL para React\n */\nexport function ACLProvider<TContext = any>({\n engine,\n user: initialUser = null,\n children,\n}: ACLProviderProps<TContext>) {\n const [user, setUser] = useState<User<TContext> | null>(initialUser);\n\n /**\n * Verifica se usuário tem permissão\n */\n const can = useCallback(\n (\n action: PermissionAction,\n resource?: ResourceType,\n context?: TContext,\n ): boolean => {\n if (!user) return false;\n return engine.can(user, action, resource, context);\n },\n [engine, user],\n );\n\n /**\n * Avalia permissão com detalhes\n */\n const evaluate = useCallback(\n (\n action: PermissionAction,\n resource?: ResourceType,\n context?: TContext,\n ): EvaluationResult => {\n if (!user) {\n return {\n allowed: false,\n reason: \"No user authenticated\",\n };\n }\n return engine.evaluate(user, action, resource, context);\n },\n [engine, user],\n );\n\n /**\n * Valor do contexto memoizado\n */\n const value = useMemo<ACLContextValue<TContext>>(\n () => ({\n engine,\n user,\n setUser,\n can,\n evaluate,\n }),\n [engine, user, can, evaluate],\n );\n\n return <ACLContext.Provider value={value}>{children}</ACLContext.Provider>;\n}\n\n/**\n * Hook para acessar o contexto ACL\n */\nexport function useACLContext<TContext = any>(): ACLContextValue<TContext> {\n const context = useContext(ACLContext);\n\n if (!context) {\n throw new Error(\"useACLContext must be used within an ACLProvider\");\n }\n\n return context as ACLContextValue<TContext>;\n}\n","import { useCallback } from \"react\";\nimport { useACLContext } from \"../context\";\nimport type {\n PermissionAction,\n ResourceType,\n User,\n PermissionRule,\n RoleName,\n} from \"@shield-acl/core\";\n\n/**\n * Hook principal do ACL que expõe todas as funcionalidades\n *\n * @returns Objeto com métodos e estado do ACL\n *\n * @example\n * ```tsx\n * const { can, cannot, evaluate, user, setUser } = useACL()\n *\n * if (can(\"posts.create\")) {\n * // Usuário pode criar posts\n * }\n *\n * const result = evaluate(\"posts.edit\", \"posts\", { postId: 123 })\n * console.log(result.reason)\n * ```\n */\nexport function useACL<TContext = any>() {\n const { engine, user, setUser, can, evaluate } = useACLContext<TContext>();\n\n /**\n * Verifica se usuário NÃO tem permissão (inverso de can)\n */\n const cannot = useCallback(\n (\n action: PermissionAction,\n resource?: ResourceType,\n context?: TContext,\n ): boolean => {\n return !can(action, resource, context);\n },\n [can],\n );\n\n /**\n * Obtém todas as permissões do usuário atual\n */\n const permissions = useCallback((): PermissionRule<TContext>[] => {\n if (!user) return [];\n return engine.getUserPermissions(user);\n }, [engine, user]);\n\n /**\n * Obtém todas as roles do usuário atual\n */\n const roles = useCallback((): RoleName[] => {\n if (!user) return [];\n return user.roles;\n }, [user]);\n\n /**\n * Limpa o cache do engine\n */\n const clearCache = useCallback(() => {\n engine.clearCache();\n }, [engine]);\n\n return {\n // Estado\n user,\n setUser,\n\n // Verificações\n can,\n cannot,\n evaluate,\n\n // Dados\n permissions,\n roles,\n\n // Engine\n engine,\n\n // Utilidades\n clearCache,\n };\n}\n\n/**\n * Type helper para inferir o tipo de contexto do useACL\n */\nexport type UseACLReturn<TContext = any> = ReturnType<typeof useACL<TContext>>;\n","import { useMemo } from \"react\";\nimport { useACLContext } from \"../context\";\nimport type { PermissionAction, ResourceType } from \"@shield-acl/core\";\n\n/**\n * Hook para verificação simples de permissão com memoização\n *\n * @param action - Ação a verificar\n * @param resource - Recurso opcional\n * @param context - Contexto adicional opcional\n * @returns boolean indicando se tem permissão\n *\n * @example\n * ```tsx\n * // Verificação simples\n * const canCreatePost = useCan(\"posts.create\")\n *\n * // Com recurso\n * const canEditUser = useCan(\"users.edit\", \"users\")\n *\n * // Com contexto\n * const canEditSpecificPost = useCan(\"posts.edit\", \"posts\", { postId: 123 })\n *\n * if (canCreatePost) {\n * return <CreatePostButton />\n * }\n * ```\n */\nexport function useCan<TContext = any>(\n action: PermissionAction,\n resource?: ResourceType,\n context?: TContext,\n): boolean {\n const { can, user } = useACLContext<TContext>();\n\n // Memoiza o resultado baseado nos parâmetros e no usuário\n return useMemo(() => {\n return can(action, resource, context);\n }, [can, action, resource, context, user]);\n}\n\n/**\n * Hook para verificação negativa de permissão com memoização\n * Útil quando você quer mostrar algo quando o usuário NÃO tem permissão\n *\n * @param action - Ação a verificar\n * @param resource - Recurso opcional\n * @param context - Contexto adicional opcional\n * @returns boolean indicando se NÃO tem permissão\n *\n * @example\n * ```tsx\n * const cannotDelete = useCannot(\"posts.delete\", \"posts\", { postId: 123 })\n *\n * if (cannotDelete) {\n * return <DisabledDeleteButton />\n * }\n * ```\n */\nexport function useCannot<TContext = any>(\n action: PermissionAction,\n resource?: ResourceType,\n context?: TContext,\n): boolean {\n const canResult = useCan(action, resource, context);\n return !canResult;\n}\n","import { useMemo } from \"react\";\nimport { useACLContext } from \"../context\";\nimport type { PermissionAction, ResourceType } from \"@shield-acl/core\";\n\n/**\n * Estrutura de uma verificação de permissão\n */\nexport interface PermissionCheck<TContext = any> {\n action: PermissionAction;\n resource?: ResourceType;\n context?: TContext;\n}\n\n/**\n * Hook que verifica se o usuário tem QUALQUER uma das permissões listadas (OR)\n *\n * @param permissions - Array de permissões para verificar\n * @returns boolean indicando se tem pelo menos uma das permissões\n *\n * @example\n * ```tsx\n * // Verificar se pode criar OU editar posts\n * const canModifyPosts = useCanAny([\n * { action: \"posts.create\" },\n * { action: \"posts.edit\" }\n * ])\n *\n * // Com recursos diferentes\n * const canAccessContent = useCanAny([\n * { action: \"posts.read\", resource: \"posts\" },\n * { action: \"pages.read\", resource: \"pages\" },\n * { action: \"admin.access\" }\n * ])\n *\n * // Com contexto específico\n * const canInteractWithPost = useCanAny([\n * { action: \"posts.edit\", resource: \"posts\", context: { postId: 123 } },\n * { action: \"posts.moderate\", resource: \"posts\" },\n * { action: \"admin.override\" }\n * ])\n * ```\n */\nexport function useCanAny<TContext = any>(\n permissions: PermissionCheck<TContext>[],\n): boolean {\n const { can, user } = useACLContext<TContext>();\n\n // Memoiza o resultado baseado nas permissões e no usuário\n return useMemo(() => {\n // Se não há permissões para verificar, retorna false\n if (!permissions || permissions.length === 0) {\n return false;\n }\n\n // Verifica se tem pelo menos uma das permissões\n return permissions.some((permission) =>\n can(permission.action, permission.resource, permission.context),\n );\n }, [can, permissions, user]);\n}\n\n/**\n * Versão simplificada do useCanAny que aceita apenas ações como strings\n *\n * @param actions - Array de ações para verificar\n * @returns boolean indicando se tem pelo menos uma das permissões\n *\n * @example\n * ```tsx\n * // Verificação simples de múltiplas ações\n * const canManageUsers = useCanAnyAction([\n * \"users.create\",\n * \"users.edit\",\n * \"users.delete\"\n * ])\n * ```\n */\nexport function useCanAnyAction(actions: PermissionAction[]): boolean {\n const permissions = useMemo(\n () => actions.map((action) => ({ action })),\n [actions],\n );\n\n return useCanAny(permissions);\n}\n","import { useMemo } from \"react\";\nimport { useACLContext } from \"../context\";\nimport type { PermissionAction, ResourceType } from \"@shield-acl/core\";\nimport type { PermissionCheck } from \"./useCanAny\";\n\n/**\n * Hook que verifica se o usuário tem TODAS as permissões listadas (AND)\n *\n * @param permissions - Array de permissões para verificar\n * @returns boolean indicando se tem todas as permissões\n *\n * @example\n * ```tsx\n * // Verificar se pode criar E editar posts (ambas necessárias)\n * const canFullyManagePosts = useCanAll([\n * { action: \"posts.create\" },\n * { action: \"posts.edit\" },\n * { action: \"posts.delete\" }\n * ])\n *\n * // Verificar múltiplas permissões com recursos\n * const hasFullAccess = useCanAll([\n * { action: \"users.read\", resource: \"users\" },\n * { action: \"users.write\", resource: \"users\" },\n * { action: \"settings.manage\" }\n * ])\n *\n * // Com contexto específico\n * const canFullyControlPost = useCanAll([\n * { action: \"posts.edit\", resource: \"posts\", context: { postId: 123 } },\n * { action: \"posts.publish\", resource: \"posts\", context: { postId: 123 } },\n * { action: \"posts.delete\", resource: \"posts\", context: { postId: 123 } }\n * ])\n * ```\n */\nexport function useCanAll<TContext = any>(\n permissions: PermissionCheck<TContext>[],\n): boolean {\n const { can, user } = useACLContext<TContext>();\n\n // Memoiza o resultado baseado nas permissões e no usuário\n return useMemo(() => {\n // Se não há permissões para verificar, retorna true (vazio = todas satisfeitas)\n if (!permissions || permissions.length === 0) {\n return true;\n }\n\n // Verifica se tem TODAS as permissões\n return permissions.every((permission) =>\n can(permission.action, permission.resource, permission.context),\n );\n }, [can, permissions, user]);\n}\n\n/**\n * Versão simplificada do useCanAll que aceita apenas ações como strings\n *\n * @param actions - Array de ações para verificar\n * @returns boolean indicando se tem todas as permissões\n *\n * @example\n * ```tsx\n * // Verificação simples de múltiplas ações\n * const hasCompleteUserAccess = useCanAllActions([\n * \"users.read\",\n * \"users.create\",\n * \"users.edit\",\n * \"users.delete\"\n * ])\n * ```\n */\nexport function useCanAllActions(actions: PermissionAction[]): boolean {\n const permissions = useMemo(\n () => actions.map((action) => ({ action })),\n [actions],\n );\n\n return useCanAll(permissions);\n}\n","import { useCallback, useMemo } from \"react\";\nimport { useACLContext } from \"../context\";\nimport type { ResourceType } from \"@shield-acl/core\";\n\n/**\n * Interface com helpers CRUD para permissões\n */\nexport interface PermissionHelpers<TContext = any> {\n canRead: (resource: ResourceType, context?: TContext) => boolean;\n canCreate: (resource: ResourceType, context?: TContext) => boolean;\n canUpdate: (resource: ResourceType, context?: TContext) => boolean;\n canDelete: (resource: ResourceType, context?: TContext) => boolean;\n canManage: (resource: ResourceType, context?: TContext) => boolean;\n canList: (resource: ResourceType, context?: TContext) => boolean;\n canView: (resource: ResourceType, context?: TContext) => boolean;\n canEdit: (resource: ResourceType, context?: TContext) => boolean;\n canModify: (resource: ResourceType, context?: TContext) => boolean;\n canAccess: (resource: ResourceType, context?: TContext) => boolean;\n}\n\n/**\n * Hook que fornece helpers CRUD para verificação de permissões\n * Segue convenções comuns de nomenclatura de ações\n *\n * @returns Objeto com métodos helper para verificações CRUD\n *\n * @example\n * ```tsx\n * const { canRead, canCreate, canUpdate, canDelete, canManage } = usePermissionHelpers()\n *\n * // Verificações CRUD básicas\n * if (canRead(\"posts\")) {\n * // Pode ler posts\n * }\n *\n * if (canCreate(\"posts\")) {\n * // Pode criar posts\n * }\n *\n * // Com contexto\n * if (canUpdate(\"posts\", { postId: 123, authorId: 456 })) {\n * // Pode atualizar este post específico\n * }\n *\n * // Verificar permissão total (manage geralmente inclui todas as outras)\n * if (canManage(\"users\")) {\n * // Tem controle total sobre usuários\n * }\n * ```\n */\nexport function usePermissionHelpers<\n TContext = any,\n>(): PermissionHelpers<TContext> {\n const { can, user } = useACLContext<TContext>();\n\n /**\n * Verifica permissão de leitura (read/view/list)\n */\n const canRead = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.read`, resource, context) ||\n can(\"read\", resource, context) ||\n can(`${resource}.view`, resource, context) ||\n can(\"view\", resource, context)\n );\n },\n [can],\n );\n\n /**\n * Verifica permissão de criação\n */\n const canCreate = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.create`, resource, context) ||\n can(\"create\", resource, context) ||\n can(`${resource}.add`, resource, context) ||\n can(\"add\", resource, context)\n );\n },\n [can],\n );\n\n /**\n * Verifica permissão de atualização\n */\n const canUpdate = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.update`, resource, context) ||\n can(\"update\", resource, context) ||\n can(`${resource}.edit`, resource, context) ||\n can(\"edit\", resource, context) ||\n can(`${resource}.modify`, resource, context) ||\n can(\"modify\", resource, context)\n );\n },\n [can],\n );\n\n /**\n * Verifica permissão de exclusão\n */\n const canDelete = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.delete`, resource, context) ||\n can(\"delete\", resource, context) ||\n can(`${resource}.remove`, resource, context) ||\n can(\"remove\", resource, context)\n );\n },\n [can],\n );\n\n /**\n * Verifica permissão de gerenciamento total (todas as operações)\n */\n const canManage = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.manage`, resource, context) ||\n can(\"manage\", resource, context) ||\n can(`${resource}.*`, resource, context) ||\n can(\"*\", resource, context) ||\n // Se tem todas as permissões CRUD individuais, também pode gerenciar\n (canRead(resource, context) &&\n canCreate(resource, context) &&\n canUpdate(resource, context) &&\n canDelete(resource, context))\n );\n },\n [can, canRead, canCreate, canUpdate, canDelete],\n );\n\n /**\n * Verifica permissão de listagem (alias para read)\n */\n const canList = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.list`, resource, context) ||\n can(\"list\", resource, context) ||\n canRead(resource, context)\n );\n },\n [can, canRead],\n );\n\n /**\n * Verifica permissão de visualização (alias para read)\n */\n const canView = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.view`, resource, context) ||\n can(\"view\", resource, context) ||\n canRead(resource, context)\n );\n },\n [can, canRead],\n );\n\n /**\n * Verifica permissão de edição (alias para update)\n */\n const canEdit = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.edit`, resource, context) ||\n can(\"edit\", resource, context) ||\n canUpdate(resource, context)\n );\n },\n [can, canUpdate],\n );\n\n /**\n * Verifica permissão de modificação (alias para update)\n */\n const canModify = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.modify`, resource, context) ||\n can(\"modify\", resource, context) ||\n canUpdate(resource, context)\n );\n },\n [can, canUpdate],\n );\n\n /**\n * Verifica permissão de acesso geral (qualquer permissão no recurso)\n */\n const canAccess = useCallback(\n (resource: ResourceType, context?: TContext): boolean => {\n return (\n can(`${resource}.access`, resource, context) ||\n can(\"access\", resource, context) ||\n canRead(resource, context) ||\n canCreate(resource, context) ||\n canUpdate(resource, context) ||\n canDelete(resource, context)\n );\n },\n [can, canRead, canCreate, canUpdate, canDelete],\n );\n\n // Retorna objeto memoizado com todos os helpers\n return useMemo(\n () => ({\n canRead,\n canCreate,\n canUpdate,\n canDelete,\n canManage,\n canList,\n canView,\n canEdit,\n canModify,\n canAccess,\n }),\n [\n canRead,\n canCreate,\n canUpdate,\n canDelete,\n canManage,\n canList,\n canView,\n canEdit,\n canModify,\n canAccess,\n user,\n ],\n );\n}\n\n/**\n * Hook para verificar permissões CRUD de um recurso específico\n * Útil quando você está trabalhando com um único recurso\n *\n * @param resource - O recurso para verificar permissões\n * @returns Objeto com métodos CRUD pré-configurados para o recurso\n *\n * @example\n * ```tsx\n * const postPermissions = useResourcePermissions(\"posts\")\n *\n * if (postPermissions.canCreate()) {\n * // Pode criar posts\n * }\n *\n * if (postPermissions.canUpdate({ postId: 123 })) {\n * // Pode atualizar este post específico\n * }\n * ```\n */\nexport function useResourcePermissions<TContext = any>(resource: ResourceType) {\n const helpers = usePermissionHelpers<TContext>();\n\n return useMemo(\n () => ({\n canRead: (context?: TContext) => helpers.canRead(resource, context),\n canCreate: (context?: TContext) => helpers.canCreate(resource, context),\n canUpdate: (context?: TContext) => helpers.canUpdate(resource, context),\n canDelete: (context?: TContext) => helpers.canDelete(resource, context),\n canManage: (context?: TContext) => helpers.canManage(resource, context),\n canList: (context?: TContext) => helpers.canList(resource, context),\n canView: (context?: TContext) => helpers.canView(resource, context),\n canEdit: (context?: TContext) => helpers.canEdit(resource, context),\n canModify: (context?: TContext) => helpers.canModify(resource, context),\n canAccess: (context?: TContext) => helpers.canAccess(resource, context),\n }),\n [helpers, resource],\n );\n}\n","import { useMemo } from \"react\";\nimport { useACLContext } from \"../context\";\nimport type { PermissionRule, RoleName } from \"@shield-acl/core\";\n\n/**\n * Estrutura detalhada de permissões do usuário\n */\nexport interface UserPermissionsInfo<TContext = any> {\n /** Todas as permissões efetivas (incluindo herdadas) */\n all: PermissionRule<TContext>[];\n\n /** Permissões diretas do usuário (não herdadas) */\n direct: PermissionRule<TContext>[];\n\n /** Permissões herdadas das roles */\n inherited: PermissionRule<TContext>[];\n\n /** Permissões agrupadas por role */\n byRole: Record<RoleName, PermissionRule<TContext>[]>;\n\n /** Permissões de negação (deny) */\n denials: PermissionRule<TContext>[];\n\n /** Permissões de permissão (allow) */\n allowances: PermissionRule<TContext>[];\n\n /** Lista única de ações disponíveis */\n actions: string[];\n\n /** Lista única de recursos disponíveis */\n resources: string[];\n\n /** Contagem total de permissões */\n count: number;\n}\n\n/**\n * Hook que lista todas as permissões efetivas do usuário atual\n * Fornece uma visão detalhada e organizada das permissões\n *\n * @returns Objeto com informações detalhadas sobre as permissões\n *\n * @example\n * ```tsx\n * const permissions = usePermissions()\n *\n * // Listar todas as permissões\n * console.log(`Total de permissões: ${permissions.count}`)\n * permissions.all.forEach(perm => {\n * console.log(`- ${perm.action} on ${perm.resource}`)\n * })\n *\n * // Ver permissões por role\n * Object.entries(permissions.byRole).forEach(([role, perms]) => {\n * console.log(`Role ${role}: ${perms.length} permissões`)\n * })\n *\n * // Verificar negações explícitas\n * if (permissions.denials.length > 0) {\n * console.warn(\"Existem negações explícitas:\")\n * permissions.denials.forEach(denial => {\n * console.warn(`- Negado: ${denial.action}`)\n * })\n * }\n *\n * // Listar ações únicas disponíveis\n * console.log(\"Ações disponíveis:\", permissions.actions)\n *\n * // Listar recursos únicos\n * console.log(\"Recursos acessíveis:\", permissions.resources)\n * ```\n */\nexport function usePermissions<\n TContext = any,\n>(): UserPermissionsInfo<TContext> {\n const { engine, user } = useACLContext<TContext>();\n\n return useMemo(() => {\n // Se não há usuário, retorna estrutura vazia\n if (!user) {\n return {\n all: [],\n direct: [],\n inherited: [],\n byRole: {},\n denials: [],\n allowances: [],\n actions: [],\n resources: [],\n count: 0,\n };\n }\n\n // Obtém todas as permissões do usuário\n const allPermissions = engine.getUserPermissions(user);\n\n // Separa permissões diretas\n const directPermissions = user.permissions || [];\n\n // Calcula permissões herdadas (todas menos as diretas)\n const inheritedPermissions = allPermissions.filter(\n (perm: PermissionRule<TContext>) => !directPermissions.includes(perm),\n );\n\n // Agrupa permissões por role\n const permissionsByRole: Record<RoleName, PermissionRule<TContext>[]> = {};\n\n // Para cada role do usuário, obtém suas permissões\n user.roles.forEach((roleName: RoleName) => {\n const role = engine.getRole(roleName);\n if (role) {\n permissionsByRole[roleName] = role.permissions;\n }\n });\n\n // Separa negações e permissões\n const denials = allPermissions.filter((perm: PermissionRule<TContext>) => perm.deny === true);\n const allowances = allPermissions.filter((perm: PermissionRule<TContext>) => perm.deny !== true);\n\n // Extrai ações únicas\n const uniqueActions = new Set<string>();\n allPermissions.forEach((perm: PermissionRule<TContext>) => {\n if (Array.isArray(perm.action)) {\n perm.action.forEach((action: string) => uniqueActions.add(action));\n } else {\n uniqueActions.add(perm.action);\n }\n });\n\n // Extrai recursos únicos (ignora undefined)\n const uniqueResources = new Set<string>();\n allPermissions.forEach((perm: PermissionRule<TContext>) => {\n if (perm.resource) {\n if (Array.isArray(perm.resource)) {\n perm.resource.forEach((resource: string) => uniqueResources.add(resource));\n } else {\n uniqueResources.add(perm.resource);\n }\n }\n });\n\n return {\n all: allPermissions,\n direct: directPermissions,\n inherited: inheritedPermissions,\n byRole: permissionsByRole,\n denials,\n allowances,\n actions: Array.from(uniqueActions).sort(),\n resources: Array.from(uniqueResources).sort(),\n count: allPermissions.length,\n };\n }, [engine, user]);\n}\n\n/**\n * Hook simplificado que retorna apenas o array de permissões\n *\n * @returns Array de todas as permissões efetivas\n *\n * @example\n * ```tsx\n * const permissions = usePermissionsList()\n *\n * permissions.forEach(perm => {\n * console.log(`${perm.action} on ${perm.resource}`)\n * })\n * ```\n */\nexport function usePermissionsList<\n TContext = any,\n>(): PermissionRule<TContext>[] {\n const { all } = usePermissions<TContext>();\n return all;\n}\n\n/**\n * Hook que retorna apenas as ações disponíveis ao usuário\n *\n * @returns Array de ações únicas\n *\n * @example\n * ```tsx\n * const actions = useAvailableActions()\n *\n * // [\"posts.create\", \"posts.edit\", \"users.read\", ...]\n * console.log(\"Ações disponíveis:\", actions)\n * ```\n */\nexport function useAvailableActions(): string[] {\n const { actions } = usePermissions();\n return actions;\n}\n\n/**\n * Hook que retorna apenas os recursos acessíveis ao usuário\n *\n * @returns Array de recursos únicos\n *\n * @example\n * ```tsx\n * const resources = useAvailableResources()\n *\n * // [\"posts\", \"users\", \"settings\", ...]\n * console.log(\"Recursos acessíveis:\", resources)\n * ```\n */\nexport function useAvailableResources(): string[] {\n const { resources } = usePermissions();\n return resources;\n}\n","import { useMemo } from \"react\";\nimport { useACLContext } from \"../context\";\nimport type { EvaluationResult } from \"@shield-acl/core\";\nimport type { PermissionCheck } from \"./useCanAny\";\n\n/**\n * Resultado da verificação múltipla de permissões\n */\nexport interface MultiplePermissionResult<TContext = any> {\n /** Indica se TODAS as permissões foram permitidas */\n allAllowed: boolean;\n\n /** Indica se ALGUMA permissão foi permitida */\n anyAllowed: boolean;\n\n /** Indica se NENHUMA permissão foi permitida */\n noneAllowed: boolean;\n\n /** Contagem de permissões permitidas */\n allowedCount: number;\n\n /** Contagem de permissões negadas */\n deniedCount: number;\n\n /** Resultados individuais indexados por chave */\n results: Record<string, boolean>;\n\n /** Detalhes completos de avaliação indexados por chave */\n details: Record<string, EvaluationResult>;\n\n /** Lista de permissões permitidas */\n allowed: PermissionCheck<TContext>[];\n\n /** Lista de permissões negadas */\n denied: PermissionCheck<TContext>[];\n}\n\n/**\n * Hook que verifica múltiplas permissões e retorna um objeto detalhado com os resultados\n *\n * @param permissions - Array de permissões para verificar\n * @param keys - Array opcional de chaves customizadas para indexar resultados\n * @returns Objeto com resultados detalhados de todas as verificações\n *\n * @example\n * ```tsx\n * // Verificar múltiplas permissões com análise detalhada\n * const permissionCheck = useCanMultiple([\n * { action: \"posts.create\" },\n * { action: \"posts.edit\", resource: \"posts\" },\n * { action: \"posts.delete\", resource: \"posts\" },\n * { action: \"users.manage\", resource: \"users\" }\n * ])\n *\n * // Verificar status geral\n * if (permissionCheck.allAllowed) {\n * console.log(\"Tem todas as permissões!\")\n * } else if (permissionCheck.anyAllowed) {\n * console.log(`Tem ${permissionCheck.allowedCount} de ${permissions.length} permissões`)\n * }\n *\n * // Verificar permissões específicas por índice\n * if (permissionCheck.results[\"posts.create\"]) {\n * // Pode criar posts\n * }\n *\n * // Com chaves customizadas\n * const namedCheck = useCanMultiple(\n * [\n * { action: \"posts.create\" },\n * { action: \"posts.edit\", resource: \"posts\" }\n * ],\n * [\"createPost\", \"editPost\"] // Chaves customizadas\n * )\n *\n * if (namedCheck.results.createPost) {\n * // Pode criar posts\n * }\n *\n * // Acessar detalhes da avaliação\n * console.log(namedCheck.details.editPost.reason)\n * ```\n */\nexport function useCanMultiple<TContext = any>(\n permissions: PermissionCheck<TContext>[],\n keys?: string[],\n): MultiplePermissionResult<TContext> {\n const { can, evaluate, user } = useACLContext<TContext>();\n\n return useMemo(() => {\n const results: Record<string, boolean> = {};\n const details: Record<string, EvaluationResult> = {};\n const allowed: PermissionCheck<TContext>[] = [];\n const denied: PermissionCheck<TContext>[] = [];\n\n // Verifica cada permissão\n permissions.forEach((permission, index) => {\n // Gera chave para o resultado\n const key =\n keys?.[index] ||\n `${permission.action}${permission.resource ? `.${permission.resource}` : \"\"}`;\n\n // Avalia a permissão\n const evaluationResult = evaluate(\n permission.action,\n permission.resource,\n permission.context,\n );\n\n const isAllowed = evaluationResult.allowed;\n\n // Armazena resultados\n results[key] = isAllowed;\n details[key] = evaluationResult;\n\n // Categoriza a permissão\n if (isAllowed) {\n allowed.push(permission);\n } else {\n denied.push(permission);\n }\n });\n\n // Calcula estatísticas\n const allowedCount = allowed.length;\n const deniedCount = denied.length;\n const allAllowed = allowedCount === permissions.length;\n const anyAllowed = allowedCount > 0;\n const noneAllowed = allowedCount === 0;\n\n return {\n allAllowed,\n anyAllowed,\n noneAllowed,\n allowedCount,\n deniedCount,\n results,\n details,\n allowed,\n denied,\n };\n }, [can, evaluate, permissions, keys, user]);\n}\n\n/**\n * Hook simplificado que retorna apenas o mapa de resultados booleanos\n *\n * @param permissions - Array de permissões para verificar\n * @param keys - Array opcional de chaves customizadas\n * @returns Objeto com resultados booleanos indexados por chave\n *\n * @example\n * ```tsx\n * const canMap = useCanMap([\n * { action: \"posts.create\" },\n * { action: \"posts.edit\" },\n * { action: \"posts.delete\" }\n * ])\n *\n * // { \"posts.create\": true, \"posts.edit\": true, \"posts.delete\": false }\n *\n * if (canMap[\"posts.create\"] && canMap[\"posts.edit\"]) {\n * // Pode criar e editar\n * }\n * ```\n */\nexport function useCanMap<TContext = any>(\n permissions: PermissionCheck<TContext>[],\n keys?: string[],\n): Record<string, boolean> {\n const { results } = useCanMultiple(permissions, keys);\n return results;\n}\n\n/**\n * Hook que verifica permissões e retorna array de booleanos na mesma ordem\n *\n * @param permissions - Array de permissões para verificar\n * @returns Array de booleanos na mesma ordem das permissões\n *\n * @example\n * ```tsx\n * const [canCreate, canEdit, canDelete] = useCanArray([\n * { action: \"posts.create\" },\n * { action: \"posts.edit\" },\n * { action: \"posts.delete\" }\n * ])\n *\n * if (canCreate && canEdit) {\n * // Pode criar e editar\n * }\n * ```\n */\nexport function useCanArray<TContext = any>(\n permissions: PermissionCheck<TContext>[],\n): boolean[] {\n const { can, user } = useACLContext<TContext>();\n\n return useMemo(() => {\n return permissions.map((permission) =>\n can(permission.action, permission.resource, permission.context),\n );\n }, [can, permissions, user]);\n}\n","import { useMemo, useCallback } from \"react\";\nimport { useACLContext } from \"../context\";\nimport { usePermissionHelpers } from \"./usePermissionHelpers\";\nimport { useCanMultiple } from \"./useCanMultiple\";\nimport type { ResourceType, PermissionAction } from \"@shield-acl/core\";\n\n/**\n * Interface completa de ACL para um recurso específico\n */\nexport interface ResourceACL<TContext = any> {\n /** Nome do recurso */\n resource: ResourceType;\n\n /** Verificações CRUD básicas */\n canRead: (context?: TContext) => boolean;\n canCreate: (context?: TContext) => boolean;\n canUpdate: (context?: TContext) => boolean;\n canDelete: (context?: TContext) => boolean;\n canManage: (context?: TContext) => boolean;\n\n /** Aliases comuns */\n canList: (context?: TContext) => boolean;\n canView: (context?: TContext) => boolean;\n canEdit: (context?: TContext) => boolean;\n canModify: (context?: TContext) => boolean;\n canAccess: (context?: TContext) => boolean;\n\n /** Verificação customizada de ação */\n can: (action: PermissionAction, context?: TContext) => boolean;\n cannot: (action: PermissionAction, context?: TContext) => boolean;\n\n /** Status geral de permissões CRUD */\n permissions: {\n read: boolean;\n create: boolean;\n update: boolean;\n delete: boolean;\n manage: boolean;\n };\n\n /** Helpers de verificação múltipla */\n hasAnyPermission: boolean;\n hasAllCrudPermissions: boolean;\n hasReadOnlyAccess: boolean;\n hasWriteAccess: boolean;\n hasFullAccess: boolean;\n\n /** Lista de ações disponíveis para este recurso */\n availableActions: string[];\n}\n\n/**\n * Hook contextual que fornece interface completa de ACL para um recurso específico\n * Automaticamente deduz e organiza todas as permissões relacionadas ao recurso\n *\n * @param resource - O recurso para contextualizar as permissões\n * @returns Objeto com interface completa de ACL para o recurso\n *\n * @example\n * ```tsx\n * // Em um componente de gerenciamento de posts\n * const postsACL = useResourceACL(\"posts\")\n *\n * // Verificações CRUD básicas\n * if (!postsACL.canRead()) {\n * return <AccessDenied />\n * }\n *\n * return (\n * <div>\n * <PostList />\n *\n * {postsACL.canCreate() && (\n * <CreatePostButton />\n * )}\n *\n * {postsACL.hasWriteAccess && (\n * <BulkActions />\n * )}\n *\n * {postsACL.hasFullAccess && (\n * <AdminPanel />\n * )}\n * </div>\n * )\n *\n * // Em um componente de item específico\n * function PostItem({ post }) {\n * const postsACL = useResourceACL(\"posts\")\n *\n * // Verificação com contexto\n * const canEditThis = postsACL.canEdit({ postId: post.id })\n * const canDeleteThis = postsACL.canDelete({ postId: post.id })\n *\n * return (\n * <div>\n * <h3>{post.title}</h3>\n * {canEditThis && <EditButton />}\n * {canDeleteThis && <DeleteButton />}\n * </div>\n * )\n * }\n * ```\n */\nexport function useResourceACL<TContext = any>(\n resource: ResourceType,\n): ResourceACL<TContext> {\n const { can: canCheck, user } = useACLContext<TContext>();\n const helpers = usePermissionHelpers<TContext>();\n\n // Cria funções de verificação vinculadas ao recurso\n const canRead = useCallback(\n (context?: TContext) => helpers.canRead(resource, context),\n [helpers, resource],\n );\n\n const canCreate = useCallback(\n (context?: TContext) => helpers.canCreate(resource, context),\n [helpers, resource],\n );\n\n const canUpdate = useCallback(\n (context?: TContext) => helpers.canUpdate(resource, context),\n [helpers, resource],\n );\n\n const canDelete = useCallback(\n (context?: TContext) => helpers.canDelete(resource, context),\n [helpers, resource],\n );\n\n const canManage = useCallback(\n (context?: TContext) => helpers.canManage(resource, context),\n [helpers, resource],\n );\n\n const canList = useCallback(\n (context?: TContext) => helpers.canList(resource, context),\n [helpers, resource],\n );\n\n const canView = useCallback(\n (context?: TContext) => helpers.canView(resource, context),\n [helpers, resource],\n );\n\n const canEdit = useCallback(\n (context?: TContext) => helpers.canEdit(resource, context),\n [helpers, resource],\n );\n\n const canModify = useCallback(\n (context?: TContext) => helpers.canModify(resource, context),\n [helpers, resource],\n );\n\n const canAccess = useCallback(\n (context?: TContext) => helpers.canAccess(resource, context),\n [helpers, resource],\n );\n\n // Verificação customizada de ação\n const can = useCallback(\n (action: PermissionAction, context?: TContext) =>\n canCheck(action, resource, context),\n [canCheck, resource],\n );\n\n const cannot = useCallback(\n (action: PermissionAction, context?: TContext) =>\n !canCheck(action, resource, context),\n [canCheck, resource],\n );\n\n // Verifica permissões CRUD básicas (sem contexto)\n const crudPermissions = useCanMultiple<TContext>(\n [\n { action: `${resource}.read`, resource },\n { action: `${resource}.create`, resource },\n { action: `${resource}.update`, resource },\n { action: `${resource}.delete`, resource },\n { action: `${resource}.manage`, resource },\n ],\n [\"read\", \"create\", \"update\", \"delete\", \"manage\"],\n );\n\n // Calcula helpers de status\n const hasAnyPermission = crudPermissions.anyAllowed;\n const hasAllCrudPermissions =\n crudPermissions.results.read &&\n crudPermissions.results.create &&\n crudPermissions.results.update &&\n crudPermissions.results.delete;\n const hasReadOnlyAccess =\n crudPermissions.results.read &&\n !crudPermissions.results.create &&\n !crudPermissions.results.update &&\n !crudPermissions.results.delete;\n const hasWriteAccess =\n crudPermissions.results.create ||\n crudPermissions.results.update ||\n crudPermissions.results.delete;\n const hasFullAccess = crudPermissions.results.manage || hasAllCrudPermissions;\n\n // Lista ações disponíveis para este recurso\n const availableActions = useMemo(() => {\n const actions: string[] = [];\n\n // Ações CRUD padrão\n const standardActions = [\n \"read\",\n \"list\",\n \"view\",\n \"create\",\n \"add\",\n \"new\",\n \"update\",\n \"edit\",\n \"modify\",\n \"delete\",\n \"remove\",\n \"manage\",\n \"*\",\n ];\n\n // Verifica cada ação padrão\n standardActions.forEach((action) => {\n if (\n canCheck(`${resource}.${action}`, resource) ||\n canCheck(action, resource)\n ) {\n actions.push(`${resource}.${action}`);\n }\n });\n\n // Remove duplicatas e ordena\n return [...new Set(actions)].sort();\n }, [canCheck, resource, user]);\n\n // Retorna objeto completo\n return useMemo(\n () => ({\n resource,\n\n // Funções CRUD\n canRead,\n canCreate,\n canUpdate,\n canDelete,\n canManage,\n\n // Aliases\n canList,\n canView,\n canEdit,\n canModify,\n canAccess,\n\n // Verificação customizada\n can,\n cannot,\n\n // Status de permissões\n permissions: {\n read: crudPermissions.results.read,\n create: crudPermissions.results.create,\n update: crudPermissions.results.update,\n delete: crudPermissions.results.delete,\n manage: crudPermissions.results.manage,\n },\n\n // Helpers de status\n hasAnyPermission,\n hasAllCrudPermissions,\n hasReadOnlyAccess,\n hasWriteAccess,\n hasFullAccess,\n\n // Ações disponíveis\n availableActions,\n }),\n [\n resource,\n canRead,\n canCreate,\n canUpdate,\n canDelete,\n canManage,\n canList,\n canView,\n canEdit,\n canModify,\n canAccess,\n can,\n cannot,\n crudPermissions,\n hasAnyPermission,\n hasAllCrudPermissions,\n hasReadOnlyAccess,\n hasWriteAccess,\n hasFullAccess,\n availableActions,\n ],\n );\n}\n\n/**\n * Hook que retorna um mapa de ACL para múltiplos recursos\n * Útil quando você precisa verificar permissões de vários recursos de uma vez\n *\n * @param resources - Array de recursos\n * @returns Mapa de recursos para suas interfaces ACL\n *\n * @example\n * ```tsx\n * const acls = useMultipleResourceACL([\"posts\", \"users\", \"settings\"])\n *\n * if (acls.posts.canCreate() && acls.users.canRead()) {\n * // Pode criar posts e ler usuários\n * }\n * ```\n */\nexport function useMultipleResourceACL<TContext = any>(\n resources: ResourceType[],\n): Record<ResourceType, ResourceACL<TContext>> {\n const acls = resources.map((resource) => ({\n resource,\n acl: useResourceACL<TContext>(resource),\n }));\n\n return useMemo(() => {\n const map: Record<ResourceType, ResourceACL<TContext>> = {};\n acls.forEach(({ resource, acl }) => {\n map[resource] = acl;\n });\n return map;\n }, [acls]);\n}\n","import { useState, useEffect, useMemo, useCallback } from \"react\";\nimport { useACLContext } from \"../context\";\nimport type { PermissionAction, ResourceType } from \"@shield-acl/core\";\n\n/**\n * Estado reativo de uma permissão\n */\nexport interface PermissionState {\n /** Valor atual da permissão */\n allowed: boolean;\n\n /** Está carregando/processando */\n loading: boolean;\n\n /** Erro se houver */\n error: Error | null;\n\n /** Timestamp da última verificação */\n lastChecked: number;\n\n /** Força uma nova verificação */\n refresh: () => void;\n}\n\n/**\n * Opções para o hook usePermissionState\n */\nexport interface UsePermissionStateOptions {\n /** Intervalo de auto-atualização em ms (0 = desabilitado) */\n refreshInterval?: number;\n\n /** Callback quando a permissão muda */\n onChange?: (newValue: boolean, oldValue: boolean) => void;\n\n /** Suspender verificações quando false */\n enabled?: boolean;\n\n /** Valor inicial enquanto carrega */\n initialValue?: boolean;\n}\n\n/**\n * Hook que cria um estado reativo de permissão que auto-atualiza quando user/contexto muda\n * Útil para componentes que precisam reagir a mudanças de permissões em tempo real\n *\n * @param action - Ação a monitorar\n * @param resource - Recurso opcional\n * @param context - Contexto adicional\n * @param options - Opções de configuração\n * @returns Estado reativo da permissão\n *\n * @example\n * ```tsx\n * // Estado reativo simples\n * function FeatureToggle() {\n * const permission = usePermissionState(\"feature.premium\")\n *\n * if (permission.loading) {\n * return <Spinner />\n * }\n *\n * return (\n * <div>\n * <Switch checked={permission.allowed} disabled />\n * <span>Premium Feature: {permission.allowed ? \"Enabled\" : \"Disabled\"}</span>\n * <button onClick={permission.refresh}>Recheck</button>\n * </div>\n * )\n * }\n *\n * // Com auto-refresh e callback\n * function LivePermissionMonitor() {\n * const [log, setLog] = useState<string[]>([])\n *\n * const permission = usePermissionState(\"admin.access\", undefined, undefined, {\n * refreshInterval: 5000, // Verifica a cada 5 segundos\n * onChange: (newValue, oldValue) => {\n * setLog(prev => [...prev, `Changed from ${oldValue} to ${newValue} at ${new Date().toLocaleTimeString()}`])\n * }\n * })\n *\n * return (\n * <div>\n * <h3>Admin Access: {permission.allowed ? \"✓\" : \"✗\"}</h3>\n * <p>Last checked: {new Date(permission.lastChecked).toLocaleTimeString()}</p>\n * <ul>\n * {log.map((entry, i) => <li key={i}>{entry}</li>)}\n * </ul>\n * </div>\n * )\n * }\n * ```\n */\nexport function usePermissionState<TContext = any>(\n action: PermissionAction,\n resource?: ResourceType,\n context?: TContext,\n options: UsePermissionStateOptions = {},\n): PermissionState {\n const { can, user } = useACLContext<TContext>();\n const {\n refreshInterval = 0,\n onChange,\n enabled = true,\n initialValue = false,\n } = options;\n\n const [state, setState] = useState<PermissionState>({\n allowed: initialValue,\n loading: true,\n error: null,\n lastChecked: 0,\n refresh: () => {},\n });\n\n // Função para verificar permissão\n const checkPermission = useCallback(() => {\n if (!enabled) return;\n\n try {\n const newValue = can(action, resource, context);\n const now = Date.now();\n\n setState((prev) => {\n // Se o valor mudou, chama onChange\n if (prev.allowed !== newValue && !prev.loading && onChange) {\n onChange(newValue, prev.allowed);\n }\n\n return {\n allowed: newValue,\n loading: false,\n error: null,\n lastChecked: now,\n refresh: prev.refresh,\n };\n });\n } catch (error) {\n setState((prev) => ({\n ...prev,\n loading: false,\n error: error as Error,\n lastChecked: Date.now(),\n }));\n }\n }, [can, action, resource, context, enabled, onChange]);\n\n // Atualiza quando user, action, resource ou context mudam\n useEffect(() => {\n checkPermission();\n }, [checkPermission, user]);\n\n // Auto-refresh se configurado\n useEffect(() => {\n if (refreshInterval > 0 && enabled) {\n const interval = setInterval(checkPermission, refreshInterval);\n return () => clearInterval(interval);\n }\n }, [refreshInterval, checkPermission, enabled]);\n\n // Atualiza função refresh no estado\n useEffect(() => {\n setState((prev) => ({\n ...prev,\n refresh: checkPermission,\n }));\n }, [checkPermission]);\n\n return state;\n}\n\n/**\n * Hook que monitora múltiplas permissões com estado reativo\n *\n * @param permissions - Array de permissões para monitorar\n * @param options - Opções de configuração\n * @returns Mapa de estados de permissão\n *\n * @example\n * ```tsx\n * const permissions = useMultiplePermissionStates([\n * { action: \"posts.create\", key: \"createPost\" },\n * { action: \"posts.edit\", resource: \"posts\", key: \"editPost\" },\n * { action: \"posts.delete\", resource: \"posts\", key: \"deletePost\" }\n * ])\n *\n * return (\n * <div>\n * <Button\n * disabled={!permissions.createPost.allowed}\n * loading={permissions.createPost.loading}\n * >\n * Create Post\n * </Button>\n *\n * <Button\n * disabled={!permissions.editPost.allowed}\n * variant={permissions.editPost.allowed ? \"primary\" : \"secondary\"}\n * >\n * Edit Post\n * </Button>\n * </div>\n * )\n * ```\n */\nexport function useMultiplePermissionStates<TContext = any>(\n permissions: Array<{\n action: PermissionAction;\n resource?: ResourceType;\n context?: TContext;\n key: string;\n }>,\n options: Omit<UsePermissionStateOptions, \"onChange\"> = {},\n): Record<string, PermissionState> {\n const { can, user } = useACLContext<TContext>();\n const { refreshInterval = 0, enabled = true, initialValue = false } = options;\n\n const [states, setStates] = useState<Record<string, PermissionState>>(() => {\n const initial: Record<string, PermissionState> = {};\n permissions.forEach(({ key }) => {\n initial[key] = {\n allowed: initialValue,\n loading: true,\n error: null,\n lastChecked: 0,\n refresh: () => {},\n };\n });\n return initial;\n });\n\n // Função para verificar todas as permissões\n const checkAllPermissions = useCallback(() => {\n if (!enabled) return;\n\n const newStates: Record<string, PermissionState> = {};\n\n permissions.forEach(({ action, resource, context, key }) => {\n try {\n const allowed = can(action, resource, context);\n newStates[key] = {\n allowed,\n loading: false,\n error: null,\n lastChecked: Date.now(),\n refresh: () => {},\n };\n } catch (error) {\n newStates[key] = {\n allowed: false,\n loading: false,\n error: error as Error,\n lastChecked: Date.now(),\n refresh: () => {},\n };\n }\n });\n\n setStates((prev) => {\n // Mantém as funções refresh existentes\n Object.keys(newStates).forEach((key) => {\n if (prev[key]) {\n newStates[key].refresh = prev[key].refresh;\n }\n });\n return newStates;\n });\n }, [can, permissions, enabled]);\n\n // Atualiza quando user ou permissões mudam\n useEffect(() => {\n checkAllPermissions();\n }, [checkAllPermissions, user]);\n\n // Auto-refresh se configurado\n useEffect(() => {\n if (refreshInterval > 0 && enabled) {\n const interval = setInterval(checkAllPermissions, refreshInterval);\n return () => clearInterval(interval);\n }\n }, [refreshInterval, checkAllPermissions, enabled]);\n\n // Atualiza funções refresh\n useEffect(() => {\n setStates((prev) => {\n const updated = { ...prev };\n Object.keys(updated).forEach((key) => {\n updated[key] = {\n ...updated[key],\n refresh: checkAllPermissions,\n };\n });\n return updated;\n });\n }, [checkAllPermissions]);\n\n return states;\n}\n\n/**\n * Hook que retorna um estado booleano reativo para uma permissão\n * Versão simplificada do usePermissionState\n *\n * @par