@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.
154 lines (145 loc) • 4.64 kB
JavaScript
// src/plugins/ReactClientComponentPlugin.ts
import { createKilpiClientPlugin } from "@kilpi/client";
import "@kilpi/core";
// src/hooks/useIsAuthorized.ts
import { useEffect as useEffect3, useState as useState2 } from "react";
// src/hooks/useCacheClearSignal.ts
import { useEffect as useEffect2, useState } from "react";
// src/hooks/useWrapRef.ts
import { useEffect, useRef } from "react";
function useWrapRef(t) {
const ref = useRef(t);
useEffect(() => {
ref.current = t;
}, [t]);
return ref;
}
// src/hooks/useCacheClearSignal.ts
function useCacheClearSignal(client, onCacheCleared) {
const [signal, setSignal] = useState(0);
const onCacheClearedRef = useWrapRef(onCacheCleared);
useEffect2(() => {
return client.onCacheClear(() => {
setSignal(signal + 1);
onCacheClearedRef.current?.();
});
}, [client, setSignal, onCacheClearedRef]);
return signal;
}
// src/hooks/useIsAuthorized.ts
function createUseIsAuthorized(KilpiClient) {
return function useIsAuthorized(key, ...inputs) {
const [value, setValue] = useState2({
status: "idle",
isAuthorized: null,
error: null
});
const cacheSignal = useCacheClearSignal(KilpiClient, () => {
setValue({ status: "idle", isAuthorized: null, error: null });
});
useEffect3(() => {
let isMounted = true;
const abortController = new AbortController();
async function fetchIsAuthorized() {
if (isMounted) setValue({ status: "loading", error: null, isAuthorized: null });
try {
const isAuthorized = await KilpiClient.fetchIsAuthorized({
key,
resource: inputs[0],
queryOptions: { signal: abortController.signal }
});
if (isMounted) setValue({ status: "success", error: null, isAuthorized });
} catch (error) {
if (isMounted) setValue({ status: "error", error, isAuthorized: null });
}
}
fetchIsAuthorized();
return () => {
isMounted = false;
abortController.abort();
};
}, [setValue, cacheSignal]);
return Object.assign(value, {
isLoading: value.status === "loading",
isError: value.status === "error",
isSuccess: value.status === "success",
isIdle: value.status === "idle"
});
};
}
// src/components/ClientAccess.tsx
function createClientAccess(KilpiClient) {
const useIsAuthorized = createUseIsAuthorized(KilpiClient);
function ClientAccess(props) {
const query = useIsAuthorized(props.to, ...[props.to, props.on]);
switch (query.status) {
case "error":
return props.Error ?? null;
case "loading":
case "idle":
return props.Loading ?? null;
case "success":
return props.children;
}
}
return ClientAccess;
}
// src/hooks/useSubject.ts
import { useEffect as useEffect4, useState as useState3 } from "react";
function createUseSubject(KilpiClient) {
return function useSubject() {
const [value, setValue] = useState3({
status: "idle",
subject: null,
error: null
});
const cacheSignal = useCacheClearSignal(KilpiClient, () => {
setValue({ status: "idle", subject: null, error: null });
});
useEffect4(() => {
let isMounted = true;
const abortController = new AbortController();
async function fetchSubject() {
if (isMounted) setValue({ status: "loading", subject: null, error: null });
try {
const subject = await KilpiClient.fetchSubject({
queryOptions: { signal: abortController.signal }
});
if (isMounted) setValue({ status: "success", subject, error: null });
} catch (error) {
if (isMounted) setValue({ status: "error", subject: null, error });
}
}
fetchSubject();
return () => {
isMounted = false;
abortController.abort();
};
}, [setValue, cacheSignal]);
return Object.assign(value, {
isLoading: value.status === "loading",
isError: value.status === "error",
isSuccess: value.status === "success",
isIdle: value.status === "idle"
});
};
}
// src/plugins/ReactClientComponentPlugin.ts
function ReactClientComponentPlugin() {
return createKilpiClientPlugin((Client) => {
return {
ReactClient: {
createComponents() {
return {
useSubject: createUseSubject(Client),
useIsAuthorized: createUseIsAuthorized(Client),
ClientAccess: createClientAccess(Client)
};
}
}
};
});
}
export {
ReactClientComponentPlugin
};