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.

125 lines (119 loc) 5.32 kB
import * as react from 'react'; import * as _kilpi_client from '@kilpi/client'; import { AnyKilpiClient, KilpiClientPolicy, KilpiClient } from '@kilpi/client'; import { PolicysetActions, Decision, GrantedDecision, DeniedDecision, AnyKilpiCore } from '@kilpi/core'; /** * Input type */ type UseAuthorizeOptions = { isDisabled?: boolean; }; /** * UseAuthorizeStatus */ type UseAuthorizeStatus = "idle" | "pending" | "error" | "success"; /** * Sub-utility type for just the status and flags */ type UseAuthorizeStatusWithFlags<TStatus extends UseAuthorizeStatus> = { status: TStatus; isIdle: TStatus extends "idle" ? true : false; isError: TStatus extends "error" ? true : false; isSuccess: TStatus extends "success" ? true : false; isPending: TStatus extends "pending" ? true : false; }; /** * Utility type to get status with flags to an object */ type UseAuthorizeReturnForStatus<TStatus extends UseAuthorizeStatus, TDecision extends null | Decision<any>> = UseAuthorizeStatusWithFlags<TStatus> & { error: TStatus extends "error" ? unknown : null; isDisabled: boolean; decision: TDecision; granted: TDecision extends { granted: true; } ? true : false; }; /** * Discriminated return type by status. Implemented this way to ensure typescript * is better able to deduce the types when narrowing or using `Extract<...>`. Two * separate discriminators for `status = success` based on `granted` flag. */ type UseAuthorizeReturn<TClient extends AnyKilpiClient, TAction extends PolicysetActions<TClient["$$infer"]["policies"]>> = UseAuthorizeReturnForStatus<"idle", null> | UseAuthorizeReturnForStatus<"pending", null> | UseAuthorizeReturnForStatus<"error", null> | UseAuthorizeReturnForStatus<"success", GrantedDecision<TClient["$$infer"]["subject"]>> | UseAuthorizeReturnForStatus<"success", DeniedDecision>; /** * The type of a KilpiClientPolicy extension. */ interface KilpiClientPolicyExtension_ReactClientPlugin<TClient extends AnyKilpiClient, TAction extends PolicysetActions<TClient["$$infer"]["policies"]>> { /** * Extend policies with a useAuthorize hook for usage in client-side React components. */ useAuthorize(options?: UseAuthorizeOptions): UseAuthorizeReturn<TClient, TAction>; } /** * Augment KilpiClientPolicy with extension. */ declare module "@kilpi/client" { interface IKilpiClientPolicy<TClient extends AnyKilpiClient, TAction extends PolicysetActions<TClient["$$infer"]["policies"]>> extends KilpiClientPolicyExtension_ReactClientPlugin<TClient, TAction> { } } /** * The <Authorize /> component renders either children, Unauthorized or Pending * based on the state of an authorization decision. */ type AuthorizeClientProps<TClient extends AnyKilpiClient, TPolicy extends KilpiClientPolicy<TClient, TClient["$$infer"]["policies"]>> = { /** * The policy to evaluate. */ policy: TPolicy; /** * Disables the authorization check when true. */ isDisabled?: boolean; /** * Children that are rendered when the caller is authorized. May be a dynamic function * that depends on the decision. */ children?: React.ReactNode | ((query: Extract<UseAuthorizeReturn<TClient, TPolicy["$action"]>, { status: "success"; granted: true; }>) => React.ReactNode); /** * Children that are rendered when the caller is not authorized. May be a dynamic function * that depends on the decision. */ Unauthorized?: React.ReactNode | ((query: Extract<UseAuthorizeReturn<TClient, TPolicy["$action"]>, { status: "success"; granted: false; }>) => React.ReactNode); /** * Children that are rendered while the authorization decision is pending. */ Pending?: React.ReactNode | ((query: Extract<UseAuthorizeReturn<TClient, TPolicy["$action"]>, { status: "pending" | "idle"; }>) => React.ReactNode); /** * Children that are rendered while the authorization decision is idle (disabled). * * Unless idle is specifically overrided or set to `null`, will use the `Pending` component * instead. */ Idle?: React.ReactNode | ((query: Extract<UseAuthorizeReturn<TClient, TPolicy["$action"]>, { status: "pending" | "idle"; }>) => React.ReactNode); /** * Children that are rendered while the authorization decision is error. */ Error?: React.ReactNode | ((query: Extract<UseAuthorizeReturn<TClient, TPolicy["$action"]>, { status: "error"; }>) => React.ReactNode); }; /** * React server component plugin for automatically providing a Kilpi scope * in React Server Components and for creating the React Server Component bindings * to work with Kilpi. */ declare function ReactClientPlugin<TCore extends AnyKilpiCore>(): _kilpi_client.KilpiClientPlugin<TCore, { $createReactClientComponents(): { AuthorizeClient: <TAction extends PolicysetActions<TCore["$$infer"]["policies"]>, TPolicy extends _kilpi_client.KilpiClientPolicy<KilpiClient<TCore>, TAction> & KilpiClientPolicyExtension_ReactClientPlugin<KilpiClient<TCore>, TAction>>({ policy, children, Unauthorized, Idle, Pending, Error, isDisabled, }: AuthorizeClientProps<KilpiClient<TCore>, TPolicy>) => react.ReactNode; }; }>; export { ReactClientPlugin };