@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
TypeScript
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 };