UNPKG

@shield-acl/react

Version:

Sistema ACL (Access Control List) inteligente e granular para aplicações React

1,195 lines (1,181 loc) 34.6 kB
// src/context.tsx import { createContext, useContext, useState, useCallback, useMemo } from "react"; import { jsx } from "react/jsx-runtime"; var ACLContext = createContext(void 0); function ACLProvider({ engine, user: initialUser = null, children }) { const [user, setUser] = useState(initialUser); const can = useCallback( (action, resource, context) => { if (!user) return false; return engine.can(user, action, resource, context); }, [engine, user] ); const evaluate = useCallback( (action, resource, context) => { if (!user) { return { allowed: false, reason: "No user authenticated" }; } return engine.evaluate(user, action, resource, context); }, [engine, user] ); const value = useMemo( () => ({ engine, user, setUser, can, evaluate }), [engine, user, can, evaluate] ); return /* @__PURE__ */ jsx(ACLContext.Provider, { value, children }); } function useACLContext() { const context = useContext(ACLContext); if (!context) { throw new Error("useACLContext must be used within an ACLProvider"); } return context; } // src/hooks/useACL.ts import { useCallback as useCallback2 } from "react"; function useACL() { const { engine, user, setUser, can, evaluate } = useACLContext(); const cannot = useCallback2( (action, resource, context) => { return !can(action, resource, context); }, [can] ); const permissions = useCallback2(() => { if (!user) return []; return engine.getUserPermissions(user); }, [engine, user]); const roles = useCallback2(() => { if (!user) return []; return user.roles; }, [user]); const clearCache = useCallback2(() => { engine.clearCache(); }, [engine]); return { // Estado user, setUser, // Verificações can, cannot, evaluate, // Dados permissions, roles, // Engine engine, // Utilidades clearCache }; } // src/hooks/useCan.ts import { useMemo as useMemo2 } from "react"; function useCan(action, resource, context) { const { can, user } = useACLContext(); return useMemo2(() => { return can(action, resource, context); }, [can, action, resource, context, user]); } function useCannot(action, resource, context) { const canResult = useCan(action, resource, context); return !canResult; } // src/hooks/useCanAny.ts import { useMemo as useMemo3 } from "react"; function useCanAny(permissions) { const { can, user } = useACLContext(); return useMemo3(() => { if (!permissions || permissions.length === 0) { return false; } return permissions.some( (permission) => can(permission.action, permission.resource, permission.context) ); }, [can, permissions, user]); } function useCanAnyAction(actions) { const permissions = useMemo3( () => actions.map((action) => ({ action })), [actions] ); return useCanAny(permissions); } // src/hooks/useCanAll.ts import { useMemo as useMemo4 } from "react"; function useCanAll(permissions) { const { can, user } = useACLContext(); return useMemo4(() => { if (!permissions || permissions.length === 0) { return true; } return permissions.every( (permission) => can(permission.action, permission.resource, permission.context) ); }, [can, permissions, user]); } function useCanAllActions(actions) { const permissions = useMemo4( () => actions.map((action) => ({ action })), [actions] ); return useCanAll(permissions); } // src/hooks/usePermissionHelpers.ts import { useCallback as useCallback3, useMemo as useMemo5 } from "react"; function usePermissionHelpers() { const { can, user } = useACLContext(); const canRead = useCallback3( (resource, context) => { return can(`${resource}.read`, resource, context) || can("read", resource, context) || can(`${resource}.view`, resource, context) || can("view", resource, context); }, [can] ); const canCreate = useCallback3( (resource, context) => { return can(`${resource}.create`, resource, context) || can("create", resource, context) || can(`${resource}.add`, resource, context) || can("add", resource, context); }, [can] ); const canUpdate = useCallback3( (resource, context) => { return can(`${resource}.update`, resource, context) || can("update", resource, context) || can(`${resource}.edit`, resource, context) || can("edit", resource, context) || can(`${resource}.modify`, resource, context) || can("modify", resource, context); }, [can] ); const canDelete = useCallback3( (resource, context) => { return can(`${resource}.delete`, resource, context) || can("delete", resource, context) || can(`${resource}.remove`, resource, context) || can("remove", resource, context); }, [can] ); const canManage = useCallback3( (resource, context) => { return can(`${resource}.manage`, resource, context) || can("manage", resource, context) || can(`${resource}.*`, resource, context) || can("*", resource, context) || // Se tem todas as permissões CRUD individuais, também pode gerenciar canRead(resource, context) && canCreate(resource, context) && canUpdate(resource, context) && canDelete(resource, context); }, [can, canRead, canCreate, canUpdate, canDelete] ); const canList = useCallback3( (resource, context) => { return can(`${resource}.list`, resource, context) || can("list", resource, context) || canRead(resource, context); }, [can, canRead] ); const canView = useCallback3( (resource, context) => { return can(`${resource}.view`, resource, context) || can("view", resource, context) || canRead(resource, context); }, [can, canRead] ); const canEdit = useCallback3( (resource, context) => { return can(`${resource}.edit`, resource, context) || can("edit", resource, context) || canUpdate(resource, context); }, [can, canUpdate] ); const canModify = useCallback3( (resource, context) => { return can(`${resource}.modify`, resource, context) || can("modify", resource, context) || canUpdate(resource, context); }, [can, canUpdate] ); const canAccess = useCallback3( (resource, context) => { return can(`${resource}.access`, resource, context) || can("access", resource, context) || canRead(resource, context) || canCreate(resource, context) || canUpdate(resource, context) || canDelete(resource, context); }, [can, canRead, canCreate, canUpdate, canDelete] ); return useMemo5( () => ({ canRead, canCreate, canUpdate, canDelete, canManage, canList, canView, canEdit, canModify, canAccess }), [ canRead, canCreate, canUpdate, canDelete, canManage, canList, canView, canEdit, canModify, canAccess, user ] ); } function useResourcePermissions(resource) { const helpers = usePermissionHelpers(); return useMemo5( () => ({ canRead: (context) => helpers.canRead(resource, context), canCreate: (context) => helpers.canCreate(resource, context), canUpdate: (context) => helpers.canUpdate(resource, context), canDelete: (context) => helpers.canDelete(resource, context), canManage: (context) => helpers.canManage(resource, context), canList: (context) => helpers.canList(resource, context), canView: (context) => helpers.canView(resource, context), canEdit: (context) => helpers.canEdit(resource, context), canModify: (context) => helpers.canModify(resource, context), canAccess: (context) => helpers.canAccess(resource, context) }), [helpers, resource] ); } // src/hooks/usePermissions.ts import { useMemo as useMemo6 } from "react"; function usePermissions() { const { engine, user } = useACLContext(); return useMemo6(() => { if (!user) { return { all: [], direct: [], inherited: [], byRole: {}, denials: [], allowances: [], actions: [], resources: [], count: 0 }; } const allPermissions = engine.getUserPermissions(user); const directPermissions = user.permissions || []; const inheritedPermissions = allPermissions.filter( (perm) => !directPermissions.includes(perm) ); const permissionsByRole = {}; user.roles.forEach((roleName) => { const role = engine.getRole(roleName); if (role) { permissionsByRole[roleName] = role.permissions; } }); const denials = allPermissions.filter((perm) => perm.deny === true); const allowances = allPermissions.filter((perm) => perm.deny !== true); const uniqueActions = /* @__PURE__ */ new Set(); allPermissions.forEach((perm) => { if (Array.isArray(perm.action)) { perm.action.forEach((action) => uniqueActions.add(action)); } else { uniqueActions.add(perm.action); } }); const uniqueResources = /* @__PURE__ */ new Set(); allPermissions.forEach((perm) => { if (perm.resource) { if (Array.isArray(perm.resource)) { perm.resource.forEach((resource) => uniqueResources.add(resource)); } else { uniqueResources.add(perm.resource); } } }); return { all: allPermissions, direct: directPermissions, inherited: inheritedPermissions, byRole: permissionsByRole, denials, allowances, actions: Array.from(uniqueActions).sort(), resources: Array.from(uniqueResources).sort(), count: allPermissions.length }; }, [engine, user]); } function usePermissionsList() { const { all } = usePermissions(); return all; } function useAvailableActions() { const { actions } = usePermissions(); return actions; } function useAvailableResources() { const { resources } = usePermissions(); return resources; } // src/hooks/useCanMultiple.ts import { useMemo as useMemo7 } from "react"; function useCanMultiple(permissions, keys) { const { can, evaluate, user } = useACLContext(); return useMemo7(() => { const results = {}; const details = {}; const allowed = []; const denied = []; permissions.forEach((permission, index) => { const key = (keys == null ? void 0 : keys[index]) || `${permission.action}${permission.resource ? `.${permission.resource}` : ""}`; const evaluationResult = evaluate( permission.action, permission.resource, permission.context ); const isAllowed = evaluationResult.allowed; results[key] = isAllowed; details[key] = evaluationResult; if (isAllowed) { allowed.push(permission); } else { denied.push(permission); } }); const allowedCount = allowed.length; const deniedCount = denied.length; const allAllowed = allowedCount === permissions.length; const anyAllowed = allowedCount > 0; const noneAllowed = allowedCount === 0; return { allAllowed, anyAllowed, noneAllowed, allowedCount, deniedCount, results, details, allowed, denied }; }, [can, evaluate, permissions, keys, user]); } function useCanMap(permissions, keys) { const { results } = useCanMultiple(permissions, keys); return results; } function useCanArray(permissions) { const { can, user } = useACLContext(); return useMemo7(() => { return permissions.map( (permission) => can(permission.action, permission.resource, permission.context) ); }, [can, permissions, user]); } // src/hooks/useResourceACL.ts import { useMemo as useMemo8, useCallback as useCallback4 } from "react"; function useResourceACL(resource) { const { can: canCheck, user } = useACLContext(); const helpers = usePermissionHelpers(); const canRead = useCallback4( (context) => helpers.canRead(resource, context), [helpers, resource] ); const canCreate = useCallback4( (context) => helpers.canCreate(resource, context), [helpers, resource] ); const canUpdate = useCallback4( (context) => helpers.canUpdate(resource, context), [helpers, resource] ); const canDelete = useCallback4( (context) => helpers.canDelete(resource, context), [helpers, resource] ); const canManage = useCallback4( (context) => helpers.canManage(resource, context), [helpers, resource] ); const canList = useCallback4( (context) => helpers.canList(resource, context), [helpers, resource] ); const canView = useCallback4( (context) => helpers.canView(resource, context), [helpers, resource] ); const canEdit = useCallback4( (context) => helpers.canEdit(resource, context), [helpers, resource] ); const canModify = useCallback4( (context) => helpers.canModify(resource, context), [helpers, resource] ); const canAccess = useCallback4( (context) => helpers.canAccess(resource, context), [helpers, resource] ); const can = useCallback4( (action, context) => canCheck(action, resource, context), [canCheck, resource] ); const cannot = useCallback4( (action, context) => !canCheck(action, resource, context), [canCheck, resource] ); const crudPermissions = useCanMultiple( [ { action: `${resource}.read`, resource }, { action: `${resource}.create`, resource }, { action: `${resource}.update`, resource }, { action: `${resource}.delete`, resource }, { action: `${resource}.manage`, resource } ], ["read", "create", "update", "delete", "manage"] ); const hasAnyPermission = crudPermissions.anyAllowed; const hasAllCrudPermissions = crudPermissions.results.read && crudPermissions.results.create && crudPermissions.results.update && crudPermissions.results.delete; const hasReadOnlyAccess = crudPermissions.results.read && !crudPermissions.results.create && !crudPermissions.results.update && !crudPermissions.results.delete; const hasWriteAccess = crudPermissions.results.create || crudPermissions.results.update || crudPermissions.results.delete; const hasFullAccess = crudPermissions.results.manage || hasAllCrudPermissions; const availableActions = useMemo8(() => { const actions = []; const standardActions = [ "read", "list", "view", "create", "add", "new", "update", "edit", "modify", "delete", "remove", "manage", "*" ]; standardActions.forEach((action) => { if (canCheck(`${resource}.${action}`, resource) || canCheck(action, resource)) { actions.push(`${resource}.${action}`); } }); return [...new Set(actions)].sort(); }, [canCheck, resource, user]); return useMemo8( () => ({ resource, // Funções CRUD canRead, canCreate, canUpdate, canDelete, canManage, // Aliases canList, canView, canEdit, canModify, canAccess, // Verificação customizada can, cannot, // Status de permissões permissions: { read: crudPermissions.results.read, create: crudPermissions.results.create, update: crudPermissions.results.update, delete: crudPermissions.results.delete, manage: crudPermissions.results.manage }, // Helpers de status hasAnyPermission, hasAllCrudPermissions, hasReadOnlyAccess, hasWriteAccess, hasFullAccess, // Ações disponíveis availableActions }), [ resource, canRead, canCreate, canUpdate, canDelete, canManage, canList, canView, canEdit, canModify, canAccess, can, cannot, crudPermissions, hasAnyPermission, hasAllCrudPermissions, hasReadOnlyAccess, hasWriteAccess, hasFullAccess, availableActions ] ); } function useMultipleResourceACL(resources) { const acls = resources.map((resource) => ({ resource, acl: useResourceACL(resource) })); return useMemo8(() => { const map = {}; acls.forEach(({ resource, acl }) => { map[resource] = acl; }); return map; }, [acls]); } // src/hooks/usePermissionState.ts import { useState as useState2, useEffect, useCallback as useCallback5 } from "react"; function usePermissionState(action, resource, context, options = {}) { const { can, user } = useACLContext(); const { refreshInterval = 0, onChange, enabled = true, initialValue = false } = options; const [state, setState] = useState2({ allowed: initialValue, loading: true, error: null, lastChecked: 0, refresh: () => { } }); const checkPermission = useCallback5(() => { if (!enabled) return; try { const newValue = can(action, resource, context); const now = Date.now(); setState((prev) => { if (prev.allowed !== newValue && !prev.loading && onChange) { onChange(newValue, prev.allowed); } return { allowed: newValue, loading: false, error: null, lastChecked: now, refresh: prev.refresh }; }); } catch (error) { setState((prev) => ({ ...prev, loading: false, error, lastChecked: Date.now() })); } }, [can, action, resource, context, enabled, onChange]); useEffect(() => { checkPermission(); }, [checkPermission, user]); useEffect(() => { if (refreshInterval > 0 && enabled) { const interval = setInterval(checkPermission, refreshInterval); return () => clearInterval(interval); } }, [refreshInterval, checkPermission, enabled]); useEffect(() => { setState((prev) => ({ ...prev, refresh: checkPermission })); }, [checkPermission]); return state; } function useMultiplePermissionStates(permissions, options = {}) { const { can, user } = useACLContext(); const { refreshInterval = 0, enabled = true, initialValue = false } = options; const [states, setStates] = useState2(() => { const initial = {}; permissions.forEach(({ key }) => { initial[key] = { allowed: initialValue, loading: true, error: null, lastChecked: 0, refresh: () => { } }; }); return initial; }); const checkAllPermissions = useCallback5(() => { if (!enabled) return; const newStates = {}; permissions.forEach(({ action, resource, context, key }) => { try { const allowed = can(action, resource, context); newStates[key] = { allowed, loading: false, error: null, lastChecked: Date.now(), refresh: () => { } }; } catch (error) { newStates[key] = { allowed: false, loading: false, error, lastChecked: Date.now(), refresh: () => { } }; } }); setStates((prev) => { Object.keys(newStates).forEach((key) => { if (prev[key]) { newStates[key].refresh = prev[key].refresh; } }); return newStates; }); }, [can, permissions, enabled]); useEffect(() => { checkAllPermissions(); }, [checkAllPermissions, user]); useEffect(() => { if (refreshInterval > 0 && enabled) { const interval = setInterval(checkAllPermissions, refreshInterval); return () => clearInterval(interval); } }, [refreshInterval, checkAllPermissions, enabled]); useEffect(() => { setStates((prev) => { const updated = { ...prev }; Object.keys(updated).forEach((key) => { updated[key] = { ...updated[key], refresh: checkAllPermissions }; }); return updated; }); }, [checkAllPermissions]); return states; } function usePermissionBoolean(action, resource, context) { const state = usePermissionState(action, resource, context); return [state.allowed, state.loading, state.refresh]; } // src/hooks/useConditionalPermissions.ts import { useMemo as useMemo10, useCallback as useCallback6 } from "react"; function useConditionalPermissions(permissions) { const { can, user } = useACLContext(); return useMemo10(() => { return permissions.map((perm) => { var _a; const conditionMet = typeof perm.condition === "function" ? perm.condition() : perm.condition; if (!conditionMet) { return { allowed: (_a = perm.defaultValue) != null ? _a : true, // Por padrão, permite se condição não for atendida conditionMet: false, skipped: true, reason: "Condition not met - permission check skipped" }; } const allowed = can(perm.action, perm.resource, perm.context); return { allowed, conditionMet: true, skipped: false, reason: allowed ? "Condition met and permission granted" : "Condition met but permission denied" }; }); }, [permissions, can, user]); } function useConditionalPermission(condition, action, resource, context, defaultValue) { const results = useConditionalPermissions([ { condition, action, resource, context, defaultValue } ]); return results[0]; } function useConditionalChecker() { const { can } = useACLContext(); return useCallback6( (condition, action, resource, context, defaultValue = true) => { const conditionMet = typeof condition === "function" ? condition() : condition; if (!conditionMet) { return { allowed: defaultValue, conditionMet: false, skipped: true, reason: "Condition not met - permission check skipped" }; } const allowed = can(action, resource, context); return { allowed, conditionMet: true, skipped: false, reason: allowed ? "Condition met and permission granted" : "Condition met but permission denied" }; }, [can] ); } function useCombinedConditionalPermission(mode, conditions, action, resource, context, defaultValue = true) { const combinedCondition = useMemo10(() => { const evaluatedConditions = conditions.map( (c) => typeof c === "function" ? c() : c ); return mode === "all" ? evaluatedConditions.every((c) => c) : evaluatedConditions.some((c) => c); }, [mode, conditions]); return useConditionalPermission( combinedCondition, action, resource, context, defaultValue ); } // src/hooks/useEvaluate.ts import { useCallback as useCallback7, useMemo as useMemo11 } from "react"; function useEvaluate() { const { evaluate } = useACLContext(); return evaluate; } function useEvaluationResult(action, resource, context) { const { evaluate, user } = useACLContext(); return useMemo11(() => { return evaluate(action, resource, context); }, [evaluate, action, resource, context, user]); } function usePermissionAnalysis() { const { evaluate, user } = useACLContext(); const explainDenial = useCallback7( (action, resource, context) => { const result = evaluate(action, resource, context); if (result.allowed) { return "Permiss\xE3o concedida"; } return result.reason || "Permiss\xE3o negada por raz\xE3o desconhecida"; }, [evaluate] ); const findMatchingRule = useCallback7( (action, resource, context) => { const result = evaluate(action, resource, context); return result.matchedRule || null; }, [evaluate] ); const testPermission = useCallback7( (action, resource, contexts) => { if (!contexts || contexts.length === 0) { const result = evaluate(action, resource); return [{ context: void 0, ...result }]; } return contexts.map((context) => ({ context, ...evaluate(action, resource, context) })); }, [evaluate] ); return useMemo11( () => ({ explainDenial, findMatchingRule, testPermission }), [explainDenial, findMatchingRule, testPermission, user] ); } // src/hooks/useRoleHierarchy.ts import { useMemo as useMemo12, useCallback as useCallback8 } from "react"; function useRoleHierarchy() { const { engine, user } = useACLContext(); const { allRoles, directRoles, inheritedRoles, inheritanceMap } = useMemo12(() => { if (!user) { return { allRoles: [], directRoles: [], inheritedRoles: [], inheritanceMap: {} }; } const direct = user.roles; const all = new Set(direct); const inheritance = {}; const collectInheritedRoles = (roleName, visited = /* @__PURE__ */ new Set()) => { if (visited.has(roleName)) return; visited.add(roleName); const role = engine.getRole(roleName); if (!role) return; inheritance[roleName] = role.inherits || []; if (role.inherits) { role.inherits.forEach((inheritedRole) => { all.add(inheritedRole); collectInheritedRoles(inheritedRole, visited); }); } }; direct.forEach((roleName) => collectInheritedRoles(roleName)); const allArray = Array.from(all); const inherited = allArray.filter((role) => !direct.includes(role)); return { allRoles: allArray, directRoles: direct, inheritedRoles: inherited, inheritanceMap: inheritance }; }, [engine, user]); const hierarchyTree = useMemo12(() => { if (!user) return []; const buildNode = (roleName, direct) => { var _a; const role = engine.getRole(roleName); const children = ((_a = role == null ? void 0 : role.inherits) == null ? void 0 : _a.map((child) => buildNode(child, false))) || []; return { name: roleName, direct, children }; }; return directRoles.map((roleName) => buildNode(roleName, true)); }, [engine, user, directRoles]); const hasRole = useCallback8( (roleName) => { return allRoles.includes(roleName); }, [allRoles] ); const hasAnyRole = useCallback8( (roleNames) => { return roleNames.some((role) => allRoles.includes(role)); }, [allRoles] ); const hasAllRoles = useCallback8( (roleNames) => { return roleNames.every((role) => allRoles.includes(role)); }, [allRoles] ); const getRoleDetails = useCallback8( (roleName) => { return engine.getRole(roleName); }, [engine] ); return { allRoles, directRoles, inheritedRoles, inheritanceMap, hierarchyTree, hasRole, hasAnyRole, hasAllRoles, getRoleDetails }; } function useHasRole(roleNames, mode = "any") { const { hasRole, hasAnyRole, hasAllRoles } = useRoleHierarchy(); return useMemo12(() => { const roles = Array.isArray(roleNames) ? roleNames : [roleNames]; if (roles.length === 1) { return hasRole(roles[0]); } return mode === "all" ? hasAllRoles(roles) : hasAnyRole(roles); }, [roleNames, mode, hasRole, hasAnyRole, hasAllRoles]); } function useRoleInfo(roleName) { const { getRoleDetails } = useRoleHierarchy(); return useMemo12(() => { return getRoleDetails(roleName); }, [getRoleDetails, roleName]); } // src/hooks/usePermissionChange.ts import { useEffect as useEffect2, useRef, useCallback as useCallback9 } from "react"; function usePermissionChange(action, resource, callback) { const { can, user } = useACLContext(); const previousValueRef = useRef(null); const previousUserRef = useRef(user); useEffect2(() => { var _a; const currentValue = can(action, resource); if (previousValueRef.current === null) { previousValueRef.current = currentValue; previousUserRef.current = user; return; } const hasPermissionChanged = currentValue !== previousValueRef.current; const hasUserChanged = (user == null ? void 0 : user.id) !== ((_a = previousUserRef.current) == null ? void 0 : _a.id); if (hasPermissionChanged || hasUserChanged) { callback(currentValue, previousValueRef.current, { action, resource, user }); previousValueRef.current = currentValue; previousUserRef.current = user; } }, [can, user, action, resource, callback]); } function useMultiplePermissionChange(permissions, callback) { const { can, user } = useACLContext(); const previousValuesRef = useRef(/* @__PURE__ */ new Map()); const previousUserRef = useRef(user); useEffect2(() => { var _a; const changes = []; let hasAnyChange = false; const hasUserChanged = (user == null ? void 0 : user.id) !== ((_a = previousUserRef.current) == null ? void 0 : _a.id); permissions.forEach(({ action, resource }) => { const key = `${action}:${resource || "none"}`; const currentValue = can(action, resource); const previousValue = previousValuesRef.current.get(key); if (previousValue === void 0 || hasUserChanged) { previousValuesRef.current.set(key, currentValue); if (previousValue !== void 0) { hasAnyChange = true; changes.push({ action, resource, newValue: currentValue, previousValue }); } } else if (currentValue !== previousValue) { hasAnyChange = true; previousValuesRef.current.set(key, currentValue); changes.push({ action, resource, newValue: currentValue, previousValue }); } }); if (hasAnyChange) { callback(changes); } previousUserRef.current = user; }, [can, user, permissions, callback]); } function usePermissionEffect(action, resource, onGain, onLose) { usePermissionChange(action, resource, (newValue, previousValue) => { if (newValue && !previousValue && onGain) { onGain(); } else if (!newValue && previousValue && onLose) { onLose(); } }); } function usePermissionChangeDetector() { const { can } = useACLContext(); return useCallback9( (action, resource) => { const initialValue = can(action, resource); return { action, resource, previousValue: initialValue, get currentValue() { return can(action, resource); }, hasChanged() { return this.currentValue !== this.previousValue; } }; }, [can] ); } // src/components.tsx import { cloneElement, isValidElement } from "react"; import { Fragment, jsx as jsx2 } from "react/jsx-runtime"; function Can({ action, resource, context, children, fallback = null, passThrough = false }) { const allowed = useCan(action, resource, context); if (allowed) { return /* @__PURE__ */ jsx2(Fragment, { children }); } if (passThrough && isValidElement(children)) { return cloneElement(children, { disabled: true, "data-permission-denied": true, "aria-disabled": true }); } return /* @__PURE__ */ jsx2(Fragment, { children: fallback }); } function Cannot({ action, resource, context, children, passThrough = false }) { const allowed = useCan(action, resource, context); if (allowed && !passThrough) { return null; } if (allowed && passThrough && isValidElement(children)) { return cloneElement(children, { disabled: false, "data-permission-granted": true, "aria-disabled": false }); } return /* @__PURE__ */ jsx2(Fragment, { children }); } function IfCan({ action, resource, context, yes, no = null }) { const allowed = useCan(action, resource, context); return /* @__PURE__ */ jsx2(Fragment, { children: allowed ? yes : no }); } function CanAny({ permissions, children, fallback = null }) { const canAny = permissions.some( (perm) => useCan(perm.action, perm.resource, perm.context) ); return /* @__PURE__ */ jsx2(Fragment, { children: canAny ? children : fallback }); } function CanAll({ permissions, children, fallback = null }) { const canAll = permissions.every( (perm) => useCan(perm.action, perm.resource, perm.context) ); return /* @__PURE__ */ jsx2(Fragment, { children: canAll ? children : fallback }); } function withCan(Component, action, resource, options) { return function WithCanComponent(props) { var _a; const allowed = useCan(action, resource, props.context); if (!allowed) { (_a = options == null ? void 0 : options.onDenied) == null ? void 0 : _a.call(options); if (options == null ? void 0 : options.fallback) { const FallbackComponent = options.fallback; return /* @__PURE__ */ jsx2(FallbackComponent, { ...props }); } if ((options == null ? void 0 : options.redirectTo) && typeof window !== "undefined") { window.location.href = options.redirectTo; } return null; } return /* @__PURE__ */ jsx2(Component, { ...props }); }; } function PermissionClass({ action, resource, context, className, deniedClassName = "", children }) { const allowed = useCan(action, resource, context); if (!isValidElement(children)) { return null; } const appliedClassName = allowed ? className : deniedClassName; const existingClassName = children.props.className || ""; return cloneElement(children, { className: `${existingClassName} ${appliedClassName}`.trim(), "data-permission": allowed ? "granted" : "denied" }); } export { ACLProvider, Can, CanAll, CanAny, Cannot, IfCan, PermissionClass, useACL, useACLContext, useAvailableActions, useAvailableResources, useCan, useCanAll, useCanAllActions, useCanAny, useCanAnyAction, useCanArray, useCanMap, useCanMultiple, useCannot, useCombinedConditionalPermission, useConditionalChecker, useConditionalPermission, useConditionalPermissions, useEvaluate, useEvaluationResult, useHasRole, useMultiplePermissionChange, useMultiplePermissionStates, useMultipleResourceACL, usePermissionAnalysis, usePermissionBoolean, usePermissionChange, usePermissionChangeDetector, usePermissionEffect, usePermissionHelpers, usePermissionState, usePermissions, usePermissionsList, useResourceACL, useResourcePermissions, useRoleHierarchy, useRoleInfo, withCan }; //# sourceMappingURL=index.mjs.map