UNPKG

@kilpi/react-client

Version:

Kilpi React Client Components · Kilpi is the authorization framework for full-stack TypeScript applications, designed for flexible, powerful, agnostic, intuitive and developer friendly authorization.

217 lines (209 loc) 6.34 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { ReactClientPlugin: () => ReactClientPlugin }); module.exports = __toCommonJS(index_exports); // src/plugins/ReactClientPlugin.ts var import_client2 = require("@kilpi/client"); // src/components/AuthorizeClient.tsx function create_AuthorizeClient(client) { void client; return function AuthorizeClient({ policy, children, Unauthorized, Idle, Pending, Error: Error2, isDisabled }) { const query = policy.useAuthorize({ isDisabled }); switch (query.status) { // Handle pending, idle and error states with custom functions case "pending": { return typeof Pending === "function" ? Pending(query) : Pending ?? null; } case "idle": { if (Idle === void 0) { return typeof Pending === "function" ? Pending(query) : Pending ?? null; } return typeof Idle === "function" ? Idle(query) : Idle ?? null; } case "error": { return typeof Error2 === "function" ? Error2(query) : Error2 ?? null; } // Success: Decide component to render based on granted case "success": { if (query.granted) { return typeof children === "function" ? children(query) : children ?? null; } return typeof Unauthorized === "function" ? Unauthorized(query) : Unauthorized ?? null; } } }; } // src/hooks/useAuthorize.ts var import_client = require("@kilpi/client"); var import_react2 = require("react"); // src/hooks/useUnmountAbortSignalRef.ts var import_react = require("react"); function useUnmountAbortSignalRef() { const controllerRef = (0, import_react.useRef)(new AbortController()); const signalRef = (0, import_react.useRef)(controllerRef.current.signal); (0, import_react.useEffect)(() => { return () => { controllerRef.current.abort(); }; }, []); return signalRef; } // src/hooks/useAuthorize.ts function create_useAuthorize(Client, policy) { void Client; function getStatusWithFlags(status) { return { status, isIdle: status === "idle", isError: status === "error", isSuccess: status === "success", isPending: status === "pending" }; } return function useAuthorize(options = {}) { const isDisabled = options.isDisabled || false; const [status, setStatus] = (0, import_react2.useState)("idle"); const [error, setError] = (0, import_react2.useState)(null); const [decision, setDecision] = (0, import_react2.useState)(null); const signalRef = useUnmountAbortSignalRef(); (0, import_react2.useEffect)(() => { return Client.$hooks.onCacheInvalidate(({ matches }) => { if (matches(policy)) { setStatus("idle"); setError(null); setDecision(null); } }); }, []); (0, import_react2.useEffect)(() => { if (isDisabled) { setStatus("idle"); setError(null); setDecision(null); return; } if (status !== "idle") { return; } setStatus("pending"); policy.authorize({ signal: signalRef.current }).then((value) => { if (signalRef.current.aborted) return; setDecision(value); setStatus("success"); }).catch((err) => { if (signalRef.current.aborted) return; setError(err); setStatus("error"); }); }, [isDisabled, status, signalRef]); switch (status) { case "idle": return { ...getStatusWithFlags(status), decision: null, granted: false, error: null, isDisabled }; case "pending": return { ...getStatusWithFlags(status), decision: null, granted: false, error: null, isDisabled }; case "error": return { ...getStatusWithFlags(status), decision: null, granted: false, error, isDisabled }; case "success": if (decision?.granted) { return { ...getStatusWithFlags(status), decision, granted: true, error: null, isDisabled }; } else { return { ...getStatusWithFlags(status), // `decision` should never be null here, but we need to satisfy TypeScript decision: decision || { granted: false }, granted: false, error: null, isDisabled }; } } }; } // src/plugins/ReactClientPlugin.ts function ReactClientPlugin() { return (0, import_client2.createKilpiClientPlugin)((Client) => { return { /** * Extend the client to allow creating components. */ extendClient() { return { $createReactClientComponents() { const AuthorizeClient = create_AuthorizeClient(Client); return { AuthorizeClient }; } }; }, /** * Extend policies to add the `useAuthorize` hook. Ensure matches extension type * with the satisfies clause. */ extendPolicy(policy) { return { useAuthorize(options) { const useAuthorize = create_useAuthorize(Client, policy); return useAuthorize(options); } }; } }; }); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ReactClientPlugin });