{"version":3,"file":"use-can.cjs","names":[],"sources":["../../src/access/use-can.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { useAccessControl } from \"./access-control-context\";\nimport type { CanParams, CanResult } from \"./types\";\n\nexport interface UseCanResult {\n    /** Whether the action is permitted. Defaults to `true` while loading is not the concern of the caller. */\n    allowed: boolean;\n    /** `true` while an async `can` check is pending. */\n    isLoading: boolean;\n    /** Optional explanation, typically present when `allowed` is `false`. */\n    reason?: string;\n}\n\nfunction normalize(result: boolean | CanResult): CanResult {\n    return typeof result === \"boolean\" ? { can: result } : result;\n}\n\n/**\n * Resolve an access check against the {@link AccessControl} in context.\n *\n * Handles sync booleans, sync {@link CanResult}, and promises of either. When\n * no provider is present, access is allowed (see `useAccessControl`). The check\n * re-runs whenever the params change.\n *\n * @param params - The action/resource being checked.\n */\nexport function useCan(params: CanParams): UseCanResult {\n    const control = useAccessControl();\n    const paramsKey = JSON.stringify(params);\n\n    const [state, setState] = useState<UseCanResult>(() =>\n        control ? { allowed: false, isLoading: true } : { allowed: true, isLoading: false },\n    );\n\n    useEffect(() => {\n        if (!control) {\n            setState({ allowed: true, isLoading: false });\n            return;\n        }\n\n        let cancelled = false;\n        setState((prev) => ({ ...prev, isLoading: true }));\n\n        Promise.resolve(control.can(params))\n            .then((raw) => {\n                if (cancelled) return;\n                const result = normalize(raw);\n                setState({ allowed: result.can, isLoading: false, reason: result.reason });\n            })\n            .catch((error: unknown) => {\n                if (cancelled) return;\n                setState({\n                    allowed: false,\n                    isLoading: false,\n                    reason: error instanceof Error ? error.message : \"access check failed\",\n                });\n            });\n\n        return () => {\n            cancelled = true;\n        };\n        // `paramsKey` is the stable stringified form of `params`.\n        // eslint-disable-next-line react-hooks/exhaustive-deps\n    }, [control, paramsKey]);\n\n    return state;\n}\n"],"mappings":"uEAaA,SAAS,EAAU,EAAwC,CACvD,OAAO,OAAO,GAAW,UAAY,CAAE,IAAK,CAAO,EAAI,CAC3D,CAWA,SAAgB,EAAO,EAAiC,CACpD,IAAM,EAAU,EAAA,iBAAiB,EAC3B,EAAY,KAAK,UAAU,CAAM,EAEjC,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,KACtB,EAAU,CAAE,QAAS,GAAO,UAAW,EAAK,EAAI,CAAE,QAAS,GAAM,UAAW,EAAM,CACtF,EAiCA,OA/BA,EAAA,EAAA,UAAA,KAAgB,CACZ,GAAI,CAAC,EAAS,CACV,EAAS,CAAE,QAAS,GAAM,UAAW,EAAM,CAAC,EAC5C,MACJ,CAEA,IAAI,EAAY,GAkBhB,OAjBA,EAAU,IAAU,CAAE,GAAG,EAAM,UAAW,EAAK,EAAE,EAEjD,QAAQ,QAAQ,EAAQ,IAAI,CAAM,CAAC,CAAC,CAC/B,KAAM,GAAQ,CACX,GAAI,EAAW,OACf,IAAM,EAAS,EAAU,CAAG,EAC5B,EAAS,CAAE,QAAS,EAAO,IAAK,UAAW,GAAO,OAAQ,EAAO,MAAO,CAAC,CAC7E,CAAC,CAAC,CACD,MAAO,GAAmB,CACnB,GACJ,EAAS,CACL,QAAS,GACT,UAAW,GACX,OAAQ,aAAiB,MAAQ,EAAM,QAAU,qBACrD,CAAC,CACL,CAAC,MAEQ,CACT,EAAY,EAChB,CAGJ,EAAG,CAAC,EAAS,CAAS,CAAC,EAEhB,CACX"}