@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
JavaScript
;
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
});