diff --git a/dist/core.js b/dist/core.js index adc57a8..5ba17b1 100644 --- a/dist/core.js +++ b/dist/core.js @@ -1,106 +1,107 @@ import J from "axios"; import { jsx as Z, jsxs as v } from "react/jsx-runtime"; import H from "keycloak-js"; -import { createContext as P, useState as y, useRef as C, useCallback as b, useEffect as K, useMemo as z, useContext as k } from "react"; +import { createContext as P, useState as y, useRef as U, useCallback as b, useEffect as K, useMemo as z, useContext as k } from "react"; import { useQueryClient as Q, useMutation as j, useQuery as Y, QueryClient as $, QueryClientProvider as _ } from "@tanstack/react-query"; import { extendTheme as ee, withDefaultColorScheme as te, ChakraProvider as re, Spinner as ne } from "@chakra-ui/react"; import { Global as oe } from "@emotion/react"; -let w = null, o = null, B = null, W = !1; -const ie = P(null), se = ({ url: e, realm: t, clientId: r }) => (o || (o = new H({ +let w = null, n = null, B = null, W = !1; +const ie = P(null), se = ({ url: e, realm: t, clientId: r }) => (n || (n = new H({ url: e, realm: t, clientId: r -})), o), ue = (e) => (w = e, w), ae = () => W, U = () => !!(o != null && o.authenticated), X = () => (o == null ? void 0 : o.token) ?? null, M = async (e = 30) => o ? o.updateToken(e) : !1, L = (e) => o == null ? void 0 : o.logout(e), Ce = (e) => o == null ? void 0 : o.login(e), V = ({ config: e, initOptions: t = {} } = {}) => { +})), n), ue = (e) => (w = e, w), ae = () => W, C = () => !!(n != null && n.authenticated), X = () => (n == null ? void 0 : n.token) ?? null, M = async (e = 30) => n ? n.updateToken(e) : !1, L = (e) => n == null ? void 0 : n.logout(e), Ue = (e) => n == null ? void 0 : n.login(e), V = ({ config: e, initOptions: t = {} } = {}) => { const r = e ?? w; if (!(r != null && r.url) || !(r != null && r.realm) || !(r != null && r.clientId)) throw new Error("Keycloak config is required."); ue(r); - const i = se(r); - return B || (B = i.init({ + const o = se(r); + return B || (B = o.init({ onLoad: "login-required", checkLoginIframe: !1, flow: "implicit", ...t - }).then((u) => (W = !0, u)).catch((u) => { - throw W = !0, u; + }).then((d) => (W = !0, d)).catch((d) => { + throw W = !0, d; })), B; }, de = ({ children: e, config: t, initOptions: r, - loading: i = null + loading: o = null }) => { - const [u, l] = y(!1), [n, s] = y(!1), [S, m] = y(null), a = C(!1), c = b(() => { - o && (s(!!o.authenticated), m(o.token ?? null)); + const [d, h] = y(!1), [a, i] = y(!1), [s, m] = y(null), u = U(!1), l = b(() => { + n && (i(!!n.authenticated), m(n.token ?? null)); }, []); - K(() => (a.current = !0, V({ config: t, initOptions: r }).then((d) => { - a.current && (s(!!d), m((o == null ? void 0 : o.token) ?? null), l(!0)); + K(() => (u.current = !0, V({ config: t, initOptions: r }).then((c) => { + u.current && (i(!!c), m((n == null ? void 0 : n.token) ?? null), h(!0)); }).catch(() => { - a.current && (s(!1), m(null), l(!0)); + u.current && (i(!1), m(null), h(!0)); }), () => { - a.current = !1; + u.current = !1; }), [t, r]); - const E = b(() => o == null ? void 0 : o.login(), []), h = b((d) => o == null ? void 0 : o.logout(d), []), F = b( - async (d = 30) => { - if (!o) return !1; - const p = await o.updateToken(d); - return c(), p; + const E = b(() => n == null ? void 0 : n.login(), []), F = b((c) => n == null ? void 0 : n.logout(c), []), S = b( + async (c = 30) => { + if (!n) return !1; + const p = await n.updateToken(c); + return l(), p; }, - [c] + [l] ), q = z( () => ({ - initialized: u, - authenticated: n, - token: S, + initialized: d, + authenticated: a, + token: s, login: E, - logout: h, - updateToken: F + logout: F, + updateToken: S }), - [u, n, S, E, h, F] + [d, a, s, E, F, S] ); - return u ? /* @__PURE__ */ Z(ie.Provider, { value: q, children: e }) : i; + return d ? /* @__PURE__ */ Z(ie.Provider, { value: q, children: e }) : o; }; let x = null; const ce = (e) => { const { api: t } = e, r = J.create({ baseURL: t.baseUrl - }), i = async () => { - (!ae() || !U()) && await V(); - }, u = async (n) => { - await i(); + }), o = async () => { + (!ae() || !C()) && await V(); + }, d = !!e.keycloak, h = async (i) => { + if (!d) return i; + await o(); let s = X(); if (s) { try { await M(5), s = X(); } catch { } - n.headers = { - ...n.headers, + i.headers = { + ...i.headers, Authorization: `Bearer ${s}` }; } - return n; - }, l = async (n) => { - var S; - const s = n.config; - if (((S = n == null ? void 0 : n.response) == null ? void 0 : S.status) === 401 && !(s != null && s._retry)) { + return i; + }, a = async (i) => { + var m; + const s = i.config; + if (((m = i == null ? void 0 : i.response) == null ? void 0 : m.status) === 401 && !(s != null && s._retry)) { s._retry = !0; try { await M(30); - const m = X(); + const u = X(); return s.headers = { ...s.headers, - Authorization: `Bearer ${m}` + Authorization: `Bearer ${u}` }, r(s); } catch { L({ redirectUri: window.location.origin }); } } - return Promise.reject(n); + return Promise.reject(i); }; - return r.interceptors.request.use(u), r.interceptors.response.use( - (n) => n, - l + return r.interceptors.request.use(h), r.interceptors.response.use( + (i) => i, + a ), { api: r }; @@ -116,23 +117,23 @@ const ce = (e) => { } } ), Fe = async (e) => (await N.get(e)).data; -function f(e) { +function O(e) { return Array.isArray(e) ? e : [e]; } function Se(e) { - return [...f(e), "list"]; + return [...O(e), "list"]; } function D(e, t) { - return [...f(e), t]; + return [...O(e), t]; } function me(e, t) { if (!t) return e; const r = new URLSearchParams(); - Object.entries(t).forEach(([u, l]) => { - l != null && l !== "" && r.append(u, l); + Object.entries(t).forEach(([d, h]) => { + h != null && h !== "" && r.append(d, h); }); - const i = r.toString(); - return i ? `${e}?${i}` : e; + const o = r.toString(); + return o ? `${e}?${o}` : e; } function qe(e, t) { return typeof e == "function" ? e(t == null ? void 0 : t.id, t) : e; @@ -144,65 +145,65 @@ function pe(e = {}) { function Ee(e, t) { return `${e.replace(/\/$/, "")}/${t}`; } -function Ue({ +function Ce({ key: e, url: t, actions: r = {}, - axiosInstance: i = N, - fetcher: u = Fe + axiosInstance: o = N, + fetcher: d = Fe }) { - const l = f(e), n = Se(e); - function s(a, c = {}) { + const h = O(e), a = Se(e); + function i(u, l = {}) { return Y({ - queryKey: a ? [...n, a] : n, - queryFn: () => u(me(t, a)), - ...c + queryKey: u ? [...a, u] : a, + queryFn: () => d(me(t, u)), + ...l }); } - function S(a, c = {}) { + function s(u, l = {}) { return Y({ - queryKey: D(e, a), - queryFn: () => u(Ee(t, a)), - enabled: !!a, - ...c + queryKey: D(e, u), + queryFn: () => d(Ee(t, u)), + enabled: !!u, + ...l }); } - function m(a, c = {}) { - const E = Q(), h = r[a]; - if (!h) - throw new Error(`Action "${a}" is not defined.`); + function m(u, l = {}) { + const E = Q(), F = r[u]; + if (!F) + throw new Error(`Action "${u}" is not defined.`); return j({ - mutationKey: [...l, a], - mutationFn: async (F = {}) => { - const q = h.method || "post", d = qe(h.url || t, F), p = h.body ? h.body(F) : h.sendRawPayload ? F : pe(F); - return (q === "delete" ? await i.delete( - d, + mutationKey: [...h, u], + mutationFn: async (S = {}) => { + const q = F.method || "post", c = qe(F.url || t, S), p = F.body ? F.body(S) : F.sendRawPayload ? S : pe(S); + return (q === "delete" ? await o.delete( + c, p && Object.keys(p).length > 0 ? { data: p } : void 0 - ) : await i[q](d, p)).data; + ) : await o[q](c, p)).data; }, - onSuccess: (...F) => { + onSuccess: (...S) => { var A; - const [q, d] = F; + const [q, c] = S; E.invalidateQueries({ - queryKey: n + queryKey: a }); - const p = (d == null ? void 0 : d.id) ?? (q == null ? void 0 : q.id); + const p = (c == null ? void 0 : c.id) ?? (q == null ? void 0 : q.id); p && E.invalidateQueries({ queryKey: D(e, p) }); - const T = typeof h.invalidateKeys == "function" ? h.invalidateKeys(q, d) : h.invalidateKeys; + const T = typeof F.invalidateKeys == "function" ? F.invalidateKeys(q, c) : F.invalidateKeys; T == null || T.forEach((G) => { E.invalidateQueries({ queryKey: G }); - }), (A = c.onSuccess) == null || A.call(c, ...F); + }), (A = l.onSuccess) == null || A.call(l, ...S); }, - ...c + ...l }); } return { - key: l, - listKey: n, - useGet: s, - useItem: S, + key: h, + listKey: a, + useGet: i, + useItem: s, useAction: m }; } @@ -210,33 +211,33 @@ const R = P(null), g = "permissions", Ze = (e) => (e == null ? void 0 : e.storag user: e = null, children: t, config: r, - loading: i = /* @__PURE__ */ Z("div", { children: "Loading permissions..." }), - errorFallback: u = /* @__PURE__ */ Z("div", { children: "Error loading permissions" }) + loading: o = /* @__PURE__ */ Z("div", { children: "Loading permissions..." }), + errorFallback: d = /* @__PURE__ */ Z("div", { children: "Error loading permissions" }) }) => { - const l = Ze(r), [n, s] = y( - () => ye(l) - ), { data: S, isLoading: m, error: a } = xe(r), c = S ?? n; + const h = Ze(r), [a, i] = y( + () => ye(h) + ), { data: s, isLoading: m, error: u } = xe(r), l = s ?? a; K(() => { - S && (Ke(l, S), s(S)); - }, [S, l]); + s && (Ke(h, s), i(s)); + }, [s, h]); const E = z( - () => Te(c), - [c] - ), h = b( - (d = "") => Xe(E, d), + () => Te(l), + [l] + ), F = b( + (c = "") => Xe(E, c), [E] - ), F = b((d = "") => !h(d), [h]), q = z( + ), S = b((c = "") => !F(c), [F]), q = z( () => ({ user: e, - can: h, - cannot: F, - permissions: c, + can: F, + cannot: S, + permissions: l, isLoading: m, - error: a + error: u }), - [e, h, F, c, m, a] + [e, F, S, l, m, u] ); - return a && !c ? u : m && !c ? i : /* @__PURE__ */ Z(R.Provider, { value: q, children: t }); + return u && !l ? d : m && !l ? o : /* @__PURE__ */ Z(R.Provider, { value: q, children: t }); }, ye = (e = g) => { if (!(typeof window > "u")) try { @@ -259,7 +260,7 @@ const R = P(null), g = "permissions", Ze = (e) => (e == null ? void 0 : e.storag } }, Te = (e) => e ? new Set(e.map((t) => t.name)) : /* @__PURE__ */ new Set(), Xe = (e, t = "") => { if (!t) return !1; - if (e.has(t) || [...e].some((i) => i.startsWith(t))) return !0; + if (e.has(t) || [...e].some((o) => o.startsWith(t))) return !0; let r = t; for (; r.includes(":"); ) if (r = r.slice(0, r.lastIndexOf(":")), e.has(`${r}:*`)) return !0; @@ -272,16 +273,16 @@ const R = P(null), g = "permissions", Ze = (e) => (e == null ? void 0 : e.storag throw new Error("Permission config requires url and clientId."); const t = X(), r = new URL(e.url); r.searchParams.set("client_id", e.clientId); - const i = await fetch(r.toString(), { + const o = await fetch(r.toString(), { method: "GET", headers: { ...t ? { Authorization: `Bearer ${t}` } : {} } }); - if (!i.ok) + if (!o.ok) throw new Error("Failed to load permissions"); - return i.json(); -}, O = () => { + return o.json(); +}, f = () => { const e = k(R); if (!e) throw new Error("usePermission must be used within PermissionProvider"); @@ -289,7 +290,7 @@ const R = P(null), g = "permissions", Ze = (e) => (e == null ? void 0 : e.storag }, xe = (e) => Y({ queryKey: I.list(e == null ? void 0 : e.clientId), queryFn: () => ze(e), - enabled: !!(e != null && e.url) && !!(e != null && e.clientId) && U(), + enabled: !!(e != null && e.url) && !!(e != null && e.clientId) && C(), staleTime: 1 / 0, refetchOnWindowFocus: !1, refetchOnReconnect: !1 @@ -298,46 +299,46 @@ const R = P(null), g = "permissions", Ze = (e) => (e == null ? void 0 : e.storag children: t, fallback: r = /* @__PURE__ */ Z("div", { children: "You are not allowed to do this" }) }) => { - const { can: i } = O(); - return i(e) ? t : r; + const { can: o } = f(); + return o(e) ? t : r; }, Ne = ({ children: e }) => { - const { can: t, permissions: r } = O(); + const { can: t, permissions: r } = f(); return r && t("admin") ? e : null; }, Re = ({ children: e }) => { - const { can: t, isLoading: r } = O(); + const { can: t, isLoading: r } = f(); return K(() => { r || t("panel_access") || L(); }, [r, t]), e; }; function ge() { - const [e, t] = y(!1), r = C(null); + const [e, t] = y(!1), r = U(null); return K(() => { if (process.env.NODE_ENV !== "production") return; - let i; - const u = async () => { - const n = await fetch(`/version.json?t=${Date.now()}`, { + let o; + const d = async () => { + const a = await fetch(`/version.json?t=${Date.now()}`, { cache: "no-store" }); - if (!n.ok) - throw new Error(`Failed to fetch version: ${n.status}`); - const s = await n.json(); - return String(s.version); + if (!a.ok) + throw new Error(`Failed to fetch version: ${a.status}`); + const i = await a.json(); + return String(i.version); }; return (async () => { try { - r.current = await u(), i = setInterval(async () => { + r.current = await d(), o = setInterval(async () => { try { - const n = await u(); - r.current && n !== r.current && (t(!0), clearInterval(i)); - } catch (n) { - console.error("Update check failed:", n); + const a = await d(); + r.current && a !== r.current && (t(!0), clearInterval(o)); + } catch (a) { + console.error("Update check failed:", a); } }, 3e4); - } catch (n) { - console.error("Initial version fetch failed:", n); + } catch (a) { + console.error("Initial version fetch failed:", a); } })(), () => { - i && clearInterval(i); + o && clearInterval(o); }; }, []), e ? /* @__PURE__ */ Z( "div", @@ -407,53 +408,53 @@ function Ie({ children: e, apiBaseUrl: t, keycloakClientId: r, - permissionClientId: i, - loading: u = /* @__PURE__ */ Z(ne, {}), - updateChecker: l = !1, - updateCheckerProps: n, - keycloakUrl: s = "https://auth.ibagher.ir", - keycloakRealm: S = "bi", + permissionClientId: o, + loading: d = /* @__PURE__ */ Z(ne, {}), + updateChecker: h = !1, + updateCheckerProps: a, + keycloakUrl: i = "https://auth.ibagher.ir", + keycloakRealm: s = "bi", permissionUrl: m = "https://api.d.aiengines.ir/user_api/v1/permissions/list", - keycloakEnabled: a, - permissionEnabled: c + keycloakEnabled: u, + permissionEnabled: l }) { - const [E, h] = y(!1), F = a ?? !!r, q = c ?? !!i, d = z( + const [E, F] = y(!1), S = u ?? !!r, q = l ?? !!o, c = z( () => ({ api: { baseUrl: t || "" }, - keycloak: F ? { - url: s, - realm: S, + keycloak: S ? { + url: i, + realm: s, clientId: r } : null, permission: q ? { url: m, - clientId: i + clientId: o } : null }), [ t, - F, - q, - s, S, + q, + i, + s, r, m, - i + o ] ); if (K(() => { - h(!0); + F(!0); }, []), K(() => { - E && le(d); - }, [E, d]), !E) + E && le(c); + }, [E, c]), !E) return null; let p = e; - return q && (p = /* @__PURE__ */ Z(be, { config: d.permission, loading: u, children: p })), F && (p = /* @__PURE__ */ Z(de, { config: d.keycloak, loading: u, children: p })), /* @__PURE__ */ v(re, { theme: we, children: [ + return q && (p = /* @__PURE__ */ Z(be, { config: c.permission, loading: d, children: p })), S && (p = /* @__PURE__ */ Z(de, { config: c.keycloak, loading: d, children: p })), /* @__PURE__ */ v(re, { theme: we, children: [ /* @__PURE__ */ Z(We, {}), /* @__PURE__ */ v(_, { client: Be, children: [ - l && /* @__PURE__ */ Z(ge, { ...n }), + h && /* @__PURE__ */ Z(ge, { ...a }), p ] }) ] }); @@ -469,7 +470,7 @@ export { Xe as checkPermission, Le as clearCachedPermissions, le as configureApi, - Ue as createApi, + Ce as createApi, Te as createPermissionSet, Fe as fetcher, he as getApi, @@ -477,13 +478,13 @@ export { X as getKeycloakToken, ze as getPermissions, V as initKeycloak, - U as isKeycloakAuthenticated, + C as isKeycloakAuthenticated, ae as isKeycloakInitialized, - Ce as loginKeycloak, + Ue as loginKeycloak, L as logoutKeycloak, I as permissionKeys, Ke as setCachedPermissions, M as updateKeycloakToken, - O as usePermission, + f as usePermission, xe as usePermissionsQuery }; diff --git a/dist/form.js b/dist/form.js index 236beee..125bcac 100644 --- a/dist/form.js +++ b/dist/form.js @@ -1,6 +1,6 @@ import { jsx as n, jsxs as M } from "react/jsx-runtime"; import { Input as I, Checkbox as ee, Textarea as re, RadioGroup as te, HStack as ne, Radio as oe, Select as le, Modal as ie, ModalOverlay as ce, ModalContent as ue, ModalHeader as se, ModalCloseButton as ae, ModalBody as de, VStack as fe, SimpleGrid as pe, ModalFooter as be, Button as A, FormControl as ve, FormLabel as me, FormErrorMessage as xe, useDisclosure as Fe } from "@chakra-ui/react"; -import { createContext as he, useContext as ge, useMemo as x, useRef as ke, useEffect as G, useState as Re, useCallback as B } from "react"; +import { useContext as he, useMemo as x, useRef as ge, useEffect as G, createContext as ke, useState as Re, useCallback as B } from "react"; import { Controller as P, useForm as Se, useWatch as Ce } from "react-hook-form"; const Me = {}, C = { create: { @@ -11,7 +11,7 @@ const Me = {}, C = { titlePrefix: "ویرایش", submitText: "ویرایش" } -}, H = he(null); +}, H = ke(null); function ye({ item: e, mode: r }) { return e ? [r, e.rowId, e.entityId, e.id].filter(Boolean).join("-") : r; } @@ -20,7 +20,7 @@ function F({ required: e, validate: r, rules: t }) { return e && (o.required = typeof e == "string" ? e : "این فیلد الزامی است."), r && (o.validate = r), o; } function v() { - const e = ge(H); + const e = he(H); if (!e) throw new Error("Field باید داخل FormModal استفاده شود."); return e; @@ -269,7 +269,7 @@ function Ae({ item: t, mode: g, isEdit: b - }) : p, [d, p, t, g, b]), V = ke(S); + }) : p, [d, p, t, g, b]), V = ge(S); G(() => { V.current = S; }, [S]); diff --git a/dist/table.js b/dist/table.js index 6e55e55..cf2efa9 100644 --- a/dist/table.js +++ b/dist/table.js @@ -3,8 +3,8 @@ import { VStack as oe, Box as _, Tbody as re, Tr as H, Td as F, Text as R, Thead import { P as ue } from "./chunks/Pagination-BFHGSAKW.js"; import { toFaDigits as q } from "./utils.js"; import { useReactTable as ae, getCoreRowModel as de, flexRender as J } from "@tanstack/react-table"; -import { createContext as me, useMemo as P, useCallback as p, useState as fe, useRef as ge, useEffect as he, useContext as be } from "react"; -const K = me(null); +import { useMemo as P, useCallback as p, useState as me, useRef as fe, useEffect as ge, createContext as he, useContext as be } from "react"; +const K = he(null); function C() { const e = be(K); if (!e) @@ -35,7 +35,7 @@ function xe({ u !== d && (a == null || a(u)); }, [z, d, a] - ), [A, U] = fe(L), m = p( + ), [A, U] = me(L), m = p( (n) => { U((i) => { const u = typeof n == "function" ? n(i) : n; @@ -43,11 +43,11 @@ function xe({ }); }, [k] - ), M = ge({ + ), M = fe({ page: d, size: h }); - he(() => { + ge(() => { if (!b) return; const n = M.current, i = n.page !== d || n.size !== h; diff --git a/package.json b/package.json index 8bc8586..3199bb6 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "./table": "./dist/table.js", "./form": "./dist/form.js" }, + "sideEffects": false, "files": [ "dist" ], diff --git a/src/core/api.js b/src/core/api.js index 27b27af..0a3e52b 100644 --- a/src/core/api.js +++ b/src/core/api.js @@ -29,7 +29,11 @@ const createApi = (config) => { // request interceptors + const shouldUseAuth = Boolean(config.keycloak); + const handleAuthRequestInterceptor = async (config) => { + if (!shouldUseAuth) return config; + await waitForKeycloak(); let token = getKeycloakToken();