@cerbos/react
Version:
A collection of React hooks for interacting with Cerbos policy decision points
200 lines • 5.61 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.useCheckResource = useCheckResource;
exports.useCheckResources = useCheckResources;
exports.useIsAllowed = useIsAllowed;
const react_1 = require("react");
const use_deep_compare_effect_1 = require("use-deep-compare-effect");
const use_cerbos_1 = require("./use-cerbos");
function useCerbosRequest(method, request, options) {
const [isLoading, setIsLoading] = (0, react_1.useState)(true);
const [data, setData] = (0, react_1.useState)();
const [error, setError] = (0, react_1.useState)();
const client = (0, use_cerbos_1.useCerbos)();
const requestMemo = (0, use_deep_compare_effect_1.useDeepCompareMemoize)(request);
const optionsMemo = (0, use_deep_compare_effect_1.useDeepCompareMemoize)(options);
const load = (0, react_1.useCallback)(async (signal) =>
// @ts-expect-error -- https://github.com/microsoft/TypeScript/issues/30581
await client[method](requestMemo, {
...optionsMemo,
signal,
}), [client, method, optionsMemo, requestMemo]);
const bundle = activeEmbeddedBundle(client);
(0, react_1.useEffect)(() => {
setIsLoading(true);
setData(undefined);
setError(undefined);
const abortController = new AbortController();
load(abortController.signal)
.then((data) => {
if (!abortController.signal.aborted) {
setIsLoading(false);
setData(data);
setError(undefined);
}
})
.catch((error) => {
if (!abortController.signal.aborted) {
setIsLoading(false);
setData(undefined);
setError(error instanceof Error
? error
: new Error("An unexpected error occurred", { cause: error }));
}
});
return () => {
abortController.abort();
};
}, [load, bundle]);
return { isLoading, data, error };
}
function activeEmbeddedBundle({ client }) {
return "loader" in client &&
typeof client.loader === "object" &&
client.loader &&
"_active" in client.loader
? client.loader._active
: undefined;
}
/**
* Check the principal's permissions on a resource.
*
* @example
* ```typescript
* import { useCheckResource } from "@cerbos/react";
*
* function SomeComponent() {
* const check = useCheckResource({
* resource: {
* kind: "document",
* id: "1",
* attr: { owner: "user@example.com" },
* },
* actions: ["view", "edit"],
* });
*
* if (check.isLoading) {
* // show spinner
* return "Loading...";
* }
*
* if (check.error) {
* // handle error
* return "Error...";
* }
*
* return (
* <div>
* {check.data.allAllowed() && <button>a button</button>}
* {check.data.isAllowed("view") && <button>another button</button>}
* </div>
* );
* }
* ```
* @public
*/
function useCheckResource(request, options) {
return useCerbosRequest("checkResource", request, options);
}
/**
* Check the principal's permissions on a set of resources.
*
* @example
* ```typescript
* import { useCheckResources } from "@cerbos/react";
*
* function SomeComponent() {
* const check = useCheckResources({
* resources: [
* {
* resource: {
* kind: "document",
* id: "1",
* attr: { owner: "user@example.com" },
* },
* actions: ["view", "edit"],
* },
* {
* resource: {
* kind: "document",
* id: "2",
* attr: { owner: "another-user@example.com" },
* },
* actions: ["view", "edit"],
* },
* ],
* });
*
* if (check.isLoading) {
* // show spinner
* return "Loading...";
* }
*
* if (check.error) {
* // handle error
* return "Error...";
* }
*
* return (
* <div>
* {check.data.allAllowed({
* kind: "document",
* id: "1",
* }) && <button>a button document 1</button>}
* {check.data.allAllowed({
* kind: "document",
* id: "2",
* }) && <button>a button document 2</button>}
* {check.data.isAllowed({
* resource: { kind: "document", id: "1" },
* action: "edit",
* }) && <button>another button for document 1</button>}
* {check.data.isAllowed({
* resource: { kind: "document", id: "2" },
* action: "edit",
* }) && <button>another button for document 2</button>}
* </div>
* );
* }
* ```
* @public
*/
function useCheckResources(request, options) {
return useCerbosRequest("checkResources", request, options);
}
/**
* Check if the principal is allowed to perform an action on a resource.
*
* @example
* ```typescript
* import { useIsAllowed } from "@cerbos/react";
*
* function SomeComponent() {
* const check = useIsAllowed({
* resource: {
* kind: "document",
* id: "1",
* attr: { owner: "user@example.com" },
* },
* action: "view",
* });
*
* if (check.isLoading) {
* // show spinner
* return "Loading...";
* }
*
* if (check.error) {
* // handle error
* return "Error...";
* }
*
* return <div>{check.data && <button>a button document 1</button>}</div>;
* }
* ```
* @public
*/
function useIsAllowed(request, options) {
return useCerbosRequest("isAllowed", request, options);
}
//# sourceMappingURL=use-cerbos-request.js.map
;