From 72a7cc7a60414e40dc4d48ad22ca389387ebdac5 Mon Sep 17 00:00:00 2001 From: Mohamadzadeh <7796733@gmail.com> Date: Thu, 11 Jun 2026 19:41:48 +0330 Subject: [PATCH] add keycloak --- dist/index.js | 1612 +++++++++++++++++++++++++++++++++++------ package.json | 3 + src/core/keycloak.jsx | 139 ++++ src/index.js | 6 + yarn.lock | 5 + 5 files changed, 1547 insertions(+), 218 deletions(-) create mode 100644 src/core/keycloak.jsx diff --git a/dist/index.js b/dist/index.js index e3f0550..5939c5f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,52 +1,59 @@ -import { jsxs as I, jsx as o } from "react/jsx-runtime"; -import { useState as y, useRef as M, useEffect as A, useCallback as _ } from "react"; -import { HStack as B, IconButton as N, Button as S, Input as E, Text as v } from "@chakra-ui/react"; -import { IoChevronForwardOutline as z, IoChevronBackOutline as V } from "react-icons/io5"; -const K = (i) => new Intl.NumberFormat("fa-IR").format(Number(i)), t = (i) => String(i).replace(/\d/g, (n) => "۰۱۲۳۴۵۶۷۸۹"[Number(n)]), D = (i) => String(i).replace(/[۰-۹]/g, (C) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(C))), O = ({ - currentPage: i, - totalPages: n, - totalCount: C, - onPageChange: d +var ze = Object.defineProperty; +var ve = (r) => { + throw TypeError(r); +}; +var je = (r, e, t) => e in r ? ze(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t; +var f = (r, e, t) => je(r, typeof e != "symbol" ? e + "" : e, t), oe = (r, e, t) => e.has(r) || ve("Cannot " + t); +var u = (r, e, t) => (oe(r, e, "read from private field"), t ? t.call(r) : e.get(r)), A = (r, e, t) => e.has(r) ? ve("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(r) : e.set(r, t), B = (r, e, t, i) => (oe(r, e, "write to private field"), i ? i.call(r, t) : e.set(r, t), t), d = (r, e, t) => (oe(r, e, "access private method"), t); +import { jsxs as O, jsx as v } from "react/jsx-runtime"; +import { useState as I, useRef as ie, useEffect as W, useCallback as H, createContext as Oe, useMemo as We, useContext as Fe } from "react"; +import { HStack as K, IconButton as G, Button as ge, Input as ke, Text as j } from "@chakra-ui/react"; +import { IoChevronForwardOutline as be, IoChevronBackOutline as ye } from "react-icons/io5"; +const yt = (r) => new Intl.NumberFormat("fa-IR").format(Number(r)), y = (r) => String(r).replace(/\d/g, (e) => "۰۱۲۳۴۵۶۷۸۹"[Number(e)]), F = (r) => String(r).replace(/[۰-۹]/g, (t) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(t))), vt = ({ + currentPage: r, + totalPages: e, + totalCount: t, + onPageChange: i }) => { - const [c, l] = y(t(i)), [a, f] = y(!1), [b, s] = y(null), x = M(null), w = [.../* @__PURE__ */ new Set([1, i, n])].filter( - (e) => e >= 1 && e <= n + const [n, o] = I(y(r)), [c, a] = I(!1), [l, h] = I(null), w = ie(null), m = [.../* @__PURE__ */ new Set([1, r, e])].filter( + (p) => p >= 1 && p <= e ); - A(() => { - if (b !== null) { - i === b && (s(null), f(!1), l(t(i))); + W(() => { + if (l !== null) { + r === l && (h(null), a(!1), o(y(r))); return; } - a || l(t(i)); - }, [i, a, b]), A(() => { - if (!a || !c || b !== null) return; - const e = parseInt(D(c), 10); - if (isNaN(e)) return; - const u = setTimeout(() => { - var m; - const r = Math.min(Math.max(e, 1), n); - r !== i ? (s(r), l(t(r)), d(r)) : (f(!1), l(t(i))), (m = x.current) == null || m.blur(); + c || o(y(r)); + }, [r, c, l]), W(() => { + if (!c || !n || l !== null) return; + const p = parseInt(F(n), 10); + if (isNaN(p)) return; + const k = setTimeout(() => { + var S; + const g = Math.min(Math.max(p, 1), e); + g !== r ? (h(g), o(y(g)), i(g)) : (a(!1), o(y(r))), (S = w.current) == null || S.blur(); }, 1e3); - return () => clearTimeout(u); + return () => clearTimeout(k); }, [ - c, - a, - b, n, - i, - d + c, + l, + e, + r, + i ]); - const k = () => { - var r, m; - const e = parseInt(D(c), 10); - if (isNaN(e)) { - l(t(i)), f(!1), s(null), (r = x.current) == null || r.blur(); + const C = () => { + var g, S; + const p = parseInt(F(n), 10); + if (isNaN(p)) { + o(y(r)), a(!1), h(null), (g = w.current) == null || g.blur(); return; } - const u = Math.min(Math.max(e, 1), n); - u !== i ? (s(u), l(t(u)), d(u)) : (l(t(i)), f(!1), s(null)), (m = x.current) == null || m.blur(); + const k = Math.min(Math.max(p, 1), e); + k !== r ? (h(k), o(y(k)), i(k)) : (o(y(r)), a(!1), h(null)), (S = w.current) == null || S.blur(); }; - return n === 0 || !C ? null : /* @__PURE__ */ I( - B, + return e === 0 || !t ? null : /* @__PURE__ */ O( + K, { justifyContent: "space-around", backgroundColor: "white", @@ -57,68 +64,68 @@ const K = (i) => new Intl.NumberFormat("fa-IR").format(Number(i)), t = (i) => St borderColor: "blue.200", w: "100%", children: [ - /* @__PURE__ */ I(B, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ - /* @__PURE__ */ o( - N, + /* @__PURE__ */ O(K, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ + /* @__PURE__ */ v( + G, { size: "md", bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => d(i - 1), - isDisabled: i === 1, - icon: /* @__PURE__ */ o(z, {}), + onClick: () => i(r - 1), + isDisabled: r === 1, + icon: /* @__PURE__ */ v(be, {}), "aria-label": "صفحه قبلی" } ), - w.map((e) => /* @__PURE__ */ o( - S, + m.map((p) => /* @__PURE__ */ v( + ge, { size: "md", px: 2, - bg: i === e ? "#4B49AC" : "#e6e6f1", - color: i === e ? "#e6e6f1" : "#4B49AC", - _hover: { bg: i === e ? "#4B49AC" : "#cbcbe8" }, - onClick: () => d(e), + bg: r === p ? "#4B49AC" : "#e6e6f1", + color: r === p ? "#e6e6f1" : "#4B49AC", + _hover: { bg: r === p ? "#4B49AC" : "#cbcbe8" }, + onClick: () => i(p), variant: "soft", - children: t(e) + children: y(p) }, - e + p )), - /* @__PURE__ */ o( - N, + /* @__PURE__ */ v( + G, { size: "md", bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => d(i + 1), - isDisabled: i === n, - icon: /* @__PURE__ */ o(V, {}), + onClick: () => i(r + 1), + isDisabled: r === e, + icon: /* @__PURE__ */ v(ye, {}), "aria-label": "صفحه بعدی" } ), - /* @__PURE__ */ o( - E, + /* @__PURE__ */ v( + ke, { - ref: x, + ref: w, type: "text", inputMode: "numeric", placeholder: "صفحه", w: "56px", - value: c, + value: n, onFocus: () => { - f(!0), s(null), l(""); + a(!0), h(null), o(""); }, - onChange: (e) => { - const u = e.target.value, r = D(u).replace(/\D/g, ""); - l(t(r)); + onChange: (p) => { + const k = p.target.value, g = F(k).replace(/\D/g, ""); + o(y(g)); }, onBlur: () => { - c || (l(t(i)), f(!1), s(null)); + n || (o(y(r)), a(!1), h(null)); }, - onKeyDown: (e) => { - e.key === "Enter" && k(); + onKeyDown: (p) => { + p.key === "Enter" && C(); }, textAlign: "center", color: "#1D2939", @@ -128,58 +135,58 @@ const K = (i) => new Intl.NumberFormat("fa-IR").format(Number(i)), t = (i) => St } ) ] }), - /* @__PURE__ */ I(B, { spacing: 2, children: [ - /* @__PURE__ */ o(v, { w: "auto", fontWeight: "bold", whiteSpace: "nowrap", children: "تعداد کل:" }), - /* @__PURE__ */ o(v, { children: t(C) }) + /* @__PURE__ */ O(K, { spacing: 2, children: [ + /* @__PURE__ */ v(j, { w: "auto", fontWeight: "bold", whiteSpace: "nowrap", children: "تعداد کل:" }), + /* @__PURE__ */ v(j, { children: y(t) }) ] }) ] } ); -}, L = ({ - currentPage: i, - totalPages: n, - totalCount: C, - onPageChange: d +}, St = ({ + currentPage: r, + totalPages: e, + totalCount: t, + onPageChange: i }) => { - const [c, l] = y(t(i)), [a, f] = y(!1), [b, s] = y(null), x = M(null), w = Array.from( - /* @__PURE__ */ new Set([1, i, i + 1, n]) - ).filter((e) => e >= 1 && e <= n).sort((e, u) => e - u); - A(() => { - if (b !== null) { - i === b && (s(null), f(!1), l(t(i))); + const [n, o] = I(y(r)), [c, a] = I(!1), [l, h] = I(null), w = ie(null), m = Array.from( + /* @__PURE__ */ new Set([1, r, r + 1, e]) + ).filter((p) => p >= 1 && p <= e).sort((p, k) => p - k); + W(() => { + if (l !== null) { + r === l && (h(null), a(!1), o(y(r))); return; } - a || l(t(i)); - }, [i, a, b]), A(() => { - if (!a || !c || b !== null) return; - const e = parseInt(D(c), 10); - if (isNaN(e)) return; - const u = setTimeout(() => { - var m; - const r = Math.min(Math.max(e, 1), n); - r !== i ? (s(r), l(t(r)), d(r)) : (f(!1), l(t(i))), (m = x.current) == null || m.blur(); + c || o(y(r)); + }, [r, c, l]), W(() => { + if (!c || !n || l !== null) return; + const p = parseInt(F(n), 10); + if (isNaN(p)) return; + const k = setTimeout(() => { + var S; + const g = Math.min(Math.max(p, 1), e); + g !== r ? (h(g), o(y(g)), i(g)) : (a(!1), o(y(r))), (S = w.current) == null || S.blur(); }, 1e3); - return () => clearTimeout(u); + return () => clearTimeout(k); }, [ - c, - a, - b, n, - i, - d + c, + l, + e, + r, + i ]); - const k = () => { - var r, m; - const e = parseInt(D(c), 10); - if (isNaN(e)) { - l(t(i)), f(!1), s(null), (r = x.current) == null || r.blur(); + const C = () => { + var g, S; + const p = parseInt(F(n), 10); + if (isNaN(p)) { + o(y(r)), a(!1), h(null), (g = w.current) == null || g.blur(); return; } - const u = Math.min(Math.max(e, 1), n); - u !== i ? (s(u), l(t(u)), d(u)) : (l(t(i)), f(!1), s(null)), (m = x.current) == null || m.blur(); + const k = Math.min(Math.max(p, 1), e); + k !== r ? (h(k), o(y(k)), i(k)) : (o(y(r)), a(!1), h(null)), (S = w.current) == null || S.blur(); }; - return n === 0 || !C ? null : /* @__PURE__ */ I( - B, + return e === 0 || !t ? null : /* @__PURE__ */ O( + K, { justifyContent: "space-around", backgroundColor: "white", @@ -190,73 +197,73 @@ const K = (i) => new Intl.NumberFormat("fa-IR").format(Number(i)), t = (i) => St borderColor: "blue.200", w: "100%", children: [ - /* @__PURE__ */ I(B, { spacing: 2, whiteSpace: "nowrap", children: [ - /* @__PURE__ */ o(v, { fontWeight: "bold", children: "صفحه" }), - /* @__PURE__ */ o(v, { children: t(i) }), - /* @__PURE__ */ o(v, { fontWeight: "bold", children: "از" }), - /* @__PURE__ */ o(v, { children: t(n) }) + /* @__PURE__ */ O(K, { spacing: 2, whiteSpace: "nowrap", children: [ + /* @__PURE__ */ v(j, { fontWeight: "bold", children: "صفحه" }), + /* @__PURE__ */ v(j, { children: y(r) }), + /* @__PURE__ */ v(j, { fontWeight: "bold", children: "از" }), + /* @__PURE__ */ v(j, { children: y(e) }) ] }), - /* @__PURE__ */ I(B, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ - /* @__PURE__ */ o( - N, + /* @__PURE__ */ O(K, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ + /* @__PURE__ */ v( + G, { size: "md", bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => d(i - 1), - isDisabled: i === 1, - icon: /* @__PURE__ */ o(z, {}), + onClick: () => i(r - 1), + isDisabled: r === 1, + icon: /* @__PURE__ */ v(be, {}), "aria-label": "صفحه قبلی" } ), - w.map((e) => /* @__PURE__ */ o( - S, + m.map((p) => /* @__PURE__ */ v( + ge, { size: "md", - bg: i === e ? "#4B49AC" : "#e6e6f1", - color: i === e ? "#e6e6f1" : "#4B49AC", - _hover: { bg: i === e ? "#4B49AC" : "#cbcbe8" }, - onClick: () => d(e), + bg: r === p ? "#4B49AC" : "#e6e6f1", + color: r === p ? "#e6e6f1" : "#4B49AC", + _hover: { bg: r === p ? "#4B49AC" : "#cbcbe8" }, + onClick: () => i(p), variant: "soft", - children: t(e) + children: y(p) }, - e + p )), - /* @__PURE__ */ o( - N, + /* @__PURE__ */ v( + G, { size: "md", bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => d(i + 1), - isDisabled: i === n, - icon: /* @__PURE__ */ o(V, {}), + onClick: () => i(r + 1), + isDisabled: r === e, + icon: /* @__PURE__ */ v(ye, {}), "aria-label": "صفحه بعدی" } ), - /* @__PURE__ */ o( - E, + /* @__PURE__ */ v( + ke, { - ref: x, + ref: w, type: "text", inputMode: "numeric", placeholder: "صفحه", w: "100px", - value: c, + value: n, onFocus: () => { - f(!0), s(null), l(""); + a(!0), h(null), o(""); }, - onChange: (e) => { - const u = e.target.value, r = D(u).replace(/\D/g, ""); - l(t(r)); + onChange: (p) => { + const k = p.target.value, g = F(k).replace(/\D/g, ""); + o(y(g)); }, onBlur: () => { - c || (l(t(i)), f(!1), s(null)); + n || (o(y(r)), a(!1), h(null)); }, - onKeyDown: (e) => { - e.key === "Enter" && k(); + onKeyDown: (p) => { + p.key === "Enter" && C(); }, textAlign: "center", color: "#1D2939", @@ -266,69 +273,69 @@ const K = (i) => new Intl.NumberFormat("fa-IR").format(Number(i)), t = (i) => St } ) ] }), - /* @__PURE__ */ I(B, { spacing: 2, whiteSpace: "nowrap", children: [ - /* @__PURE__ */ o(v, { fontWeight: "bold", children: "تعداد کل:" }), - /* @__PURE__ */ o(v, { children: t(C) }) + /* @__PURE__ */ O(K, { spacing: 2, whiteSpace: "nowrap", children: [ + /* @__PURE__ */ v(j, { fontWeight: "bold", children: "تعداد کل:" }), + /* @__PURE__ */ v(j, { children: y(t) }) ] }) ] } ); -}, H = ({ - currentPage: i, - totalPages: n, - totalCount: C, - onPageChange: d +}, Ct = ({ + currentPage: r, + totalPages: e, + totalCount: t, + onPageChange: i }) => { - const [c, l] = y(""), [a, f] = y(!1), [b, s] = y(null), x = M(null), w = b ?? i, k = _( - (p) => { - const h = Math.min(Math.max(p, 1), n); - f(!1), l(""), s(null), h !== i && d(h); + const [n, o] = I(""), [c, a] = I(!1), [l, h] = I(null), w = ie(null), m = l ?? r, C = H( + (U) => { + const E = Math.min(Math.max(U, 1), e); + a(!1), o(""), h(null), E !== r && i(E); }, - [i, n, d] - ), e = _(() => { - if (!c) { - f(!1), l(""), s(null); + [r, e, i] + ), p = H(() => { + if (!n) { + a(!1), o(""), h(null); return; } - const p = parseInt(D(c), 10); - if (isNaN(p)) { - f(!1), l(""), s(null); + const U = parseInt(F(n), 10); + if (isNaN(U)) { + a(!1), o(""), h(null); return; } - const h = Math.min(Math.max(p, 1), n); - f(!1), l(""), h !== i ? (s(h), d(h)) : s(null); - }, [c, i, n, d]); - A(() => { - var p; - a && ((p = x.current) == null || p.focus()); - }, [a]), A(() => { - b !== null && i === b && s(null); - }, [i, b]), A(() => { - if (!a || !c) return; - const p = setTimeout(() => { - e(); + const E = Math.min(Math.max(U, 1), e); + a(!1), o(""), E !== r ? (h(E), i(E)) : h(null); + }, [n, r, e, i]); + W(() => { + var U; + c && ((U = w.current) == null || U.focus()); + }, [c]), W(() => { + l !== null && r === l && h(null); + }, [r, l]), W(() => { + if (!c || !n) return; + const U = setTimeout(() => { + p(); }, 1e3); - return () => clearTimeout(p); - }, [c, a, e]); - const u = () => { - s(null), l(""), f(!0); - }, r = (p, h = !1) => /* @__PURE__ */ o( - S, + return () => clearTimeout(U); + }, [n, c, p]); + const k = () => { + h(null), o(""), a(!0); + }, g = (U, E = !1) => /* @__PURE__ */ v( + ge, { size: "md", - bg: h ? "#4B49AC" : "#e6e6f1", - color: h ? "#e6e6f1" : "#4B49AC", - _hover: { bg: h ? "#4B49AC" : "#cbcbe8" }, - onClick: h ? u : () => k(p), + bg: E ? "#4B49AC" : "#e6e6f1", + color: E ? "#e6e6f1" : "#4B49AC", + _hover: { bg: E ? "#4B49AC" : "#cbcbe8" }, + onClick: E ? k : () => C(U), variant: "soft", - children: t(p) + children: y(U) }, - p + U ); - if (n === 0 || !C) return null; - const m = n > 1 && w !== 1, j = n > 1 && w !== n; - return /* @__PURE__ */ o( - B, + if (e === 0 || !t) return null; + const S = e > 1 && m !== 1, V = e > 1 && m !== e; + return /* @__PURE__ */ v( + K, { justifyContent: "center", backgroundColor: "white", @@ -338,39 +345,39 @@ const K = (i) => new Intl.NumberFormat("fa-IR").format(Number(i)), t = (i) => St border: "1px", borderColor: "blue.200", w: "100%", - children: /* @__PURE__ */ I(B, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ - /* @__PURE__ */ o( - N, + children: /* @__PURE__ */ O(K, { spacing: 2, alignItems: "center", justifyContent: "center", children: [ + /* @__PURE__ */ v( + G, { size: "md", bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => k(w - 1), - isDisabled: w === 1, - icon: /* @__PURE__ */ o(z, {}), + onClick: () => C(m - 1), + isDisabled: m === 1, + icon: /* @__PURE__ */ v(be, {}), "aria-label": "صفحه قبلی" } ), - m && r(1), - a ? /* @__PURE__ */ o( - E, + S && g(1), + c ? /* @__PURE__ */ v( + ke, { - ref: x, + ref: w, type: "text", inputMode: "numeric", placeholder: "صفحه", w: "48px", - value: c, - onChange: (p) => { - const h = p.target.value, T = D(h).replace(/\D/g, ""); - l(t(T)); + value: n, + onChange: (U) => { + const E = U.target.value, Pe = F(E).replace(/\D/g, ""); + o(y(Pe)); }, onBlur: () => { - c ? e() : (l(""), f(!1), s(null)); + n ? p() : (o(""), a(!1), h(null)); }, - onKeyDown: (p) => { - p.key === "Enter" && e(), p.key === "Escape" && (l(""), f(!1), s(null)); + onKeyDown: (U) => { + U.key === "Enter" && p(), U.key === "Escape" && (o(""), a(!1), h(null)); }, textAlign: "center", color: "#1D2939", @@ -378,30 +385,1199 @@ const K = (i) => new Intl.NumberFormat("fa-IR").format(Number(i)), t = (i) => St minW: 0, dir: "ltr" } - ) : r(w, !0), - j && r(n), - /* @__PURE__ */ o( - N, + ) : g(m, !0), + V && g(e), + /* @__PURE__ */ v( + G, { size: "md", bg: "#e6e6f1", color: "#4B49AC", _hover: { bg: "#cbcbe8" }, - onClick: () => k(w + 1), - isDisabled: w === n, - icon: /* @__PURE__ */ o(V, {}), + onClick: () => C(m + 1), + isDisabled: m === e, + icon: /* @__PURE__ */ v(ye, {}), "aria-label": "صفحه بعدی" } ) ] }) } ); +}, Ve = "application/json"; +var N, T, $, J, M, q, b, L, s, ee, _e, Te, Ee, Ae, ae, Ie, ce, xe, Le, te, X, le, P, Re, de, z, re, Z, R, he; +class He { + /** + * @param {KeycloakConfig} config + */ + constructor(e) { + A(this, s); + /** @type {Pick, 'resolve' | 'reject'>[]} */ + A(this, N, []); + /** @type {KeycloakAdapter} */ + A(this, T); + /** @type {boolean} */ + A(this, $, !0); + /** @type {CallbackStorage} */ + A(this, J); + A(this, M, d(this, s, he).call(this, console.info)); + A(this, q, d(this, s, he).call(this, console.warn)); + /** @type {LoginIframe} */ + A(this, b, { + enable: !0, + callbackList: [], + interval: 5 + }); + /** @type {KeycloakConfig} config */ + A(this, L); + f(this, "didInitialize", !1); + f(this, "authenticated", !1); + f(this, "loginRequired", !1); + /** @type {KeycloakResponseMode} */ + f(this, "responseMode", "fragment"); + /** @type {KeycloakResponseType} */ + f(this, "responseType", "code"); + /** @type {KeycloakFlow} */ + f(this, "flow", "standard"); + /** @type {number?} */ + f(this, "timeSkew", null); + /** @type {string=} */ + f(this, "redirectUri"); + /** @type {string=} */ + f(this, "silentCheckSsoRedirectUri"); + /** @type {boolean} */ + f(this, "silentCheckSsoFallback", !0); + /** @type {KeycloakPkceMethod} */ + f(this, "pkceMethod", "S256"); + f(this, "enableLogging", !1); + /** @type {'GET' | 'POST'} */ + f(this, "logoutMethod", "GET"); + /** @type {string=} */ + f(this, "scope"); + f(this, "messageReceiveTimeout", 1e4); + /** @type {string=} */ + f(this, "idToken"); + /** @type {KeycloakTokenParsed=} */ + f(this, "idTokenParsed"); + /** @type {string=} */ + f(this, "token"); + /** @type {KeycloakTokenParsed=} */ + f(this, "tokenParsed"); + /** @type {string=} */ + f(this, "refreshToken"); + /** @type {KeycloakTokenParsed=} */ + f(this, "refreshTokenParsed"); + /** @type {string=} */ + f(this, "clientId"); + /** @type {string=} */ + f(this, "sessionId"); + /** @type {string=} */ + f(this, "subject"); + /** @type {string=} */ + f(this, "authServerUrl"); + /** @type {string=} */ + f(this, "realm"); + /** @type {KeycloakRoles=} */ + f(this, "realmAccess"); + /** @type {KeycloakResourceAccess=} */ + f(this, "resourceAccess"); + /** @type {KeycloakProfile=} */ + f(this, "profile"); + /** @type {{}=} */ + f(this, "userInfo"); + /** @type {Endpoints} */ + f(this, "endpoints"); + /** @type {number=} */ + f(this, "tokenTimeoutHandle"); + /** @type {() => void=} */ + f(this, "onAuthSuccess"); + /** @type {(errorData?: KeycloakError) => void=} */ + f(this, "onAuthError"); + /** @type {() => void=} */ + f(this, "onAuthRefreshSuccess"); + /** @type {() => void=} */ + f(this, "onAuthRefreshError"); + /** @type {() => void=} */ + f(this, "onTokenExpired"); + /** @type {() => void=} */ + f(this, "onAuthLogout"); + /** @type {(authenticated: boolean) => void=} */ + f(this, "onReady"); + /** @type {(status: 'success' | 'cancelled' | 'error', action: string) => void=} */ + f(this, "onActionUpdate"); + /** + * @param {KeycloakInitOptions} initOptions + * @returns {Promise} + */ + f(this, "init", async (e = {}) => { + var i; + if (this.didInitialize) + throw new Error("A 'Keycloak' instance can only be initialized once."); + this.didInitialize = !0, B(this, J, Xe()); + const t = ["default", "cordova", "cordova-native"]; + if (typeof e.adapter == "string" && t.includes(e.adapter) ? B(this, T, d(this, s, ee).call(this, e.adapter)) : typeof e.adapter == "object" ? B(this, T, e.adapter) : "Cordova" in window || "cordova" in window ? B(this, T, d(this, s, ee).call(this, "cordova")) : B(this, T, d(this, s, ee).call(this, "default")), typeof e.useNonce < "u" && B(this, $, e.useNonce), typeof e.checkLoginIframe < "u" && (u(this, b).enable = e.checkLoginIframe), e.checkLoginIframeInterval && (u(this, b).interval = e.checkLoginIframeInterval), e.onLoad === "login-required" && (this.loginRequired = !0), e.responseMode) + if (e.responseMode === "query" || e.responseMode === "fragment") + this.responseMode = e.responseMode; + else + throw new Error("Invalid value for responseMode"); + if (e.flow) { + switch (e.flow) { + case "standard": + this.responseType = "code"; + break; + case "implicit": + this.responseType = "id_token token"; + break; + case "hybrid": + this.responseType = "code id_token token"; + break; + default: + throw new Error("Invalid value for flow"); + } + this.flow = e.flow; + } + if (typeof e.timeSkew == "number" && (this.timeSkew = e.timeSkew), e.redirectUri && (this.redirectUri = e.redirectUri), e.silentCheckSsoRedirectUri && (this.silentCheckSsoRedirectUri = e.silentCheckSsoRedirectUri), typeof e.silentCheckSsoFallback == "boolean" && (this.silentCheckSsoFallback = e.silentCheckSsoFallback), typeof e.pkceMethod < "u") { + if (e.pkceMethod !== "S256" && e.pkceMethod !== !1) + throw new TypeError(`Invalid value for pkceMethod', expected 'S256' or false but got ${e.pkceMethod}.`); + this.pkceMethod = e.pkceMethod; + } + return typeof e.enableLogging == "boolean" && (this.enableLogging = e.enableLogging), e.logoutMethod === "POST" && (this.logoutMethod = "POST"), typeof e.scope == "string" && (this.scope = e.scope), typeof e.messageReceiveTimeout == "number" && e.messageReceiveTimeout > 0 && (this.messageReceiveTimeout = e.messageReceiveTimeout), await d(this, s, Ae).call(this), await d(this, s, xe).call(this), await d(this, s, Le).call(this, e), (i = this.onReady) == null || i.call(this, this.authenticated), this.authenticated; + }); + /** + * @param {KeycloakLoginOptions} [options] + * @returns {Promise} + */ + f(this, "login", (e) => u(this, T).login(e)); + /** + * @param {KeycloakLoginOptions} [options] + * @returns {Promise} + */ + f(this, "createLoginUrl", async (e) => { + const t = Se(), i = Se(), n = u(this, T).redirectUri(e), o = { + state: t, + nonce: i, + redirectUri: n, + loginOptions: e + }; + e != null && e.prompt && (o.prompt = e.prompt); + const c = (e == null ? void 0 : e.action) === "register" ? this.endpoints.register() : this.endpoints.authorize(); + let a = (e == null ? void 0 : e.scope) || this.scope; + const l = a ? a.split(" ") : []; + l.includes("openid") || l.unshift("openid"), a = l.join(" "); + const h = new URLSearchParams([ + [ + "client_id", + /** @type {string} */ + this.clientId + ], + ["redirect_uri", n], + ["state", t], + ["response_mode", this.responseMode], + ["response_type", this.responseType], + ["scope", a] + ]); + if (u(this, $) && h.append("nonce", i), e != null && e.prompt && h.append("prompt", e.prompt), typeof (e == null ? void 0 : e.maxAge) == "number" && h.append("max_age", e.maxAge.toString()), e != null && e.loginHint && h.append("login_hint", e.loginHint), e != null && e.idpHint && h.append("kc_idp_hint", e.idpHint), e != null && e.action && e.action !== "register" && h.append("kc_action", e.action), e != null && e.locale && h.append("ui_locales", e.locale), e != null && e.acr && h.append("claims", Ye(e.acr)), e != null && e.acrValues && h.append("acr_values", e.acrValues), this.pkceMethod) + try { + const w = $e(96), m = await Je(this.pkceMethod, w); + o.pkceCodeVerifier = w, h.append("code_challenge", m), h.append("code_challenge_method", this.pkceMethod); + } catch (w) { + throw new Error("Failed to generate PKCE challenge.", { cause: w }); + } + return u(this, J).add(o), `${c}?${h.toString()}`; + }); + /** + * @param {KeycloakLogoutOptions} [options] + * @returns {Promise} + */ + f(this, "logout", (e) => u(this, T).logout(e)); + /** + * @param {KeycloakLogoutOptions} [options] + * @returns {string} + */ + f(this, "createLogoutUrl", (e) => { + const t = (e == null ? void 0 : e.logoutMethod) ?? this.logoutMethod, i = this.endpoints.logout(); + if (t === "POST") + return i; + const n = new URLSearchParams([ + [ + "client_id", + /** @type {string} */ + this.clientId + ], + ["post_logout_redirect_uri", u(this, T).redirectUri(e)] + ]); + return this.idToken && n.append("id_token_hint", this.idToken), `${i}?${n.toString()}`; + }); + /** + * @param {KeycloakRegisterOptions} [options] + * @returns {Promise} + */ + f(this, "register", (e) => u(this, T).register(e)); + /** + * @param {KeycloakRegisterOptions} [options] + * @returns {Promise} + */ + f(this, "createRegisterUrl", (e) => this.createLoginUrl({ ...e, action: "register" })); + /** + * @param {KeycloakAccountOptions} [options] + * @returns {string} + */ + f(this, "createAccountUrl", (e) => { + const t = d(this, s, R).call(this); + if (!t) + throw new Error("Unable to create account URL, make sure the adapter is not configured using a generic OIDC provider."); + const i = new URLSearchParams([ + [ + "referrer", + /** @type {string} */ + this.clientId + ], + ["referrer_uri", u(this, T).redirectUri(e)] + ]); + return `${t}/account?${i.toString()}`; + }); + /** + * @returns {Promise} + */ + f(this, "accountManagement", () => u(this, T).accountManagement()); + /** + * @param {string} role + * @returns {boolean} + */ + f(this, "hasRealmRole", (e) => { + const t = this.realmAccess; + return !!t && t.roles.indexOf(e) >= 0; + }); + /** + * @param {string} role + * @param {string} [resource] + * @returns {boolean} + */ + f(this, "hasResourceRole", (e, t) => { + if (!this.resourceAccess) + return !1; + const i = this.resourceAccess[t || /** @type {string} */ + this.clientId]; + return !!i && i.roles.indexOf(e) >= 0; + }); + /** + * @returns {Promise} + */ + f(this, "loadUserProfile", async () => { + const e = d(this, s, R).call(this); + if (!e) + throw new Error("Unable to load user profile, make sure the adapter is not configured using a generic OIDC provider."); + const t = `${e}/account`, i = await Q(t, { + headers: [Ce(this.token)] + }); + return this.profile = i; + }); + /** + * @returns {Promise<{}>} + */ + f(this, "loadUserInfo", async () => { + const e = this.endpoints.userinfo(), t = await Q(e, { + headers: [Ce(this.token)] + }); + return this.userInfo = t; + }); + /** + * @param {number} [minValidity] + * @returns {boolean} + */ + f(this, "isTokenExpired", (e) => { + if (!this.tokenParsed || !this.refreshToken && this.flow !== "implicit") + throw new Error("Not authenticated"); + if (this.timeSkew == null) + return u(this, M).call(this, "[KEYCLOAK] Unable to determine if token is expired as timeskew is not set"), !0; + if (typeof this.tokenParsed.exp != "number") + return !1; + let t = this.tokenParsed.exp - Math.ceil((/* @__PURE__ */ new Date()).getTime() / 1e3) + this.timeSkew; + if (e) { + if (isNaN(e)) + throw new Error("Invalid minValidity"); + t -= e; + } + return t < 0; + }); + /** + * @param {number} minValidity + * @returns {Promise} + */ + f(this, "updateToken", async (e) => { + var c, a; + if (!this.refreshToken) + throw new Error("Unable to update token, no refresh token available."); + e = e || 5, u(this, b).enable && await d(this, s, X).call(this); + let t = !1; + if (e === -1 ? (t = !0, u(this, M).call(this, "[KEYCLOAK] Refreshing token: forced refresh")) : (!this.tokenParsed || this.isTokenExpired(e)) && (t = !0, u(this, M).call(this, "[KEYCLOAK] Refreshing token: token expired")), !t) + return !1; + const { promise: i, resolve: n, reject: o } = Promise.withResolvers(); + if (u(this, N).push({ resolve: n, reject: o }), u(this, N).length === 1) { + const l = this.endpoints.token(); + let h = (/* @__PURE__ */ new Date()).getTime(); + try { + const w = await ct( + l, + this.refreshToken, + /** @type {string} */ + this.clientId + ); + u(this, M).call(this, "[KEYCLOAK] Token refreshed"), h = (h + (/* @__PURE__ */ new Date()).getTime()) / 2, d(this, s, Z).call(this, w.access_token, w.refresh_token, w.id_token, h), (c = this.onAuthRefreshSuccess) == null || c.call(this); + for (let m = u(this, N).pop(); m != null; m = u(this, N).pop()) + m.resolve(!0); + } catch (w) { + u(this, q).call(this, "[KEYCLOAK] Failed to refresh token"), w instanceof Ke && w.response.status === 400 && this.clearToken(), (a = this.onAuthRefreshError) == null || a.call(this); + for (let m = u(this, N).pop(); m != null; m = u(this, N).pop()) + m.reject(w); + } + } + return await i; + }); + f(this, "clearToken", () => { + var e; + this.token && (d(this, s, Z).call(this), (e = this.onAuthLogout) == null || e.call(this), this.loginRequired && this.login()); + }); + if (typeof e != "string" && !me(e)) + throw new Error("The 'Keycloak' constructor must be provided with a configuration object, or a URL to a JSON configuration file."); + if (me(e)) { + const t = "oidcProvider" in e ? ["clientId"] : ["url", "realm", "clientId"]; + for (const i of t) + if (!(i in e)) + throw new Error(`The configuration object is missing the required '${i}' property.`); + } + globalThis.isSecureContext || u(this, q).call(this, `[KEYCLOAK] Keycloak JS must be used in a 'secure context' to function properly as it relies on browser APIs that are otherwise not available. +Continuing to run your application insecurely will lead to unexpected behavior and breakage. + +For more information see: https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts`), B(this, L, e); + } +} +N = new WeakMap(), T = new WeakMap(), $ = new WeakMap(), J = new WeakMap(), M = new WeakMap(), q = new WeakMap(), b = new WeakMap(), L = new WeakMap(), s = new WeakSet(), /** + * @param {"default" | "cordova" | "cordova-native"} type + * @returns {KeycloakAdapter} + */ +ee = function(e) { + if (e === "default") + return d(this, s, _e).call(this); + if (e === "cordova") + return u(this, b).enable = !1, d(this, s, Te).call(this); + if (e === "cordova-native") + return u(this, b).enable = !1, d(this, s, Ee).call(this); + throw new Error("invalid adapter type: " + e); +}, /** + * @returns {KeycloakAdapter} + */ +_e = function() { + const e = (t) => (t == null ? void 0 : t.redirectUri) || this.redirectUri || globalThis.location.href; + return { + login: async (t) => (window.location.assign(await this.createLoginUrl(t)), await new Promise(() => { + })), + logout: async (t) => { + if (((t == null ? void 0 : t.logoutMethod) ?? this.logoutMethod) === "GET") { + window.location.replace(this.createLogoutUrl(t)); + return; + } + const n = document.createElement("form"); + n.setAttribute("method", "POST"), n.setAttribute("action", this.createLogoutUrl(t)), n.style.display = "none"; + const o = { + id_token_hint: this.idToken, + client_id: this.clientId, + post_logout_redirect_uri: e(t) + }; + for (const [c, a] of Object.entries(o)) { + const l = document.createElement("input"); + l.setAttribute("type", "hidden"), l.setAttribute("name", c), l.setAttribute( + "value", + /** @type {string} */ + a + ), n.appendChild(l); + } + document.body.appendChild(n), n.submit(); + }, + register: async (t) => (window.location.assign(await this.createRegisterUrl(t)), await new Promise(() => { + })), + accountManagement: async () => { + const t = this.createAccountUrl(); + if (typeof t < "u") + window.location.href = t; + else + throw new Error("Not supported by the OIDC server"); + return await new Promise(() => { + }); + }, + redirectUri: e + }; +}, /** + * @returns {KeycloakAdapter} + */ +Te = function() { + const e = (c, a, l) => window.cordova && window.cordova.InAppBrowser ? window.cordova.InAppBrowser.open(c, a, l) : window.open(c, a, l), t = (c) => c && c.cordovaOptions ? Object.keys(c.cordovaOptions).reduce((a, l) => (a[l] = c.cordovaOptions[l], a), {}) : {}, i = (c) => Object.keys(c).reduce((a, l) => (a.push(l + "=" + c[l]), a), []).join(","), n = (c) => { + const a = t(c); + return a.location = "no", c && c.prompt === "none" && (a.hidden = "yes"), i(a); + }, o = () => this.redirectUri || "http://localhost"; + return { + login: async (c) => { + const a = n(c), l = await this.createLoginUrl(c), h = e(l, "_blank", a); + let w = !1, m = !1; + function C() { + m = !0, h.close(); + } + return await new Promise((p, k) => { + h.addEventListener("loadstart", async (g) => { + if (g.url.indexOf(o()) === 0) { + const S = d(this, s, P).call(this, g.url); + w = !0, C(); + try { + await d(this, s, z).call(this, S), p(); + } catch (V) { + k(V); + } + } + }), h.addEventListener("loaderror", async (g) => { + if (!w) + if (g.url.indexOf(o()) === 0) { + const S = d(this, s, P).call(this, g.url); + w = !0, C(); + try { + await d(this, s, z).call(this, S), p(); + } catch (V) { + k(V); + } + } else + k(new Error("Unable to process login.")), C(); + }), h.addEventListener("exit", function(g) { + m || k(new Error("User closed the login window.")); + }); + }); + }, + logout: async (c) => { + const a = this.createLogoutUrl(c), l = e(a, "_blank", "location=no,hidden=yes,clearcache=yes"); + let h = !1; + l.addEventListener("loadstart", (w) => { + w.url.indexOf(o()) === 0 && l.close(); + }), l.addEventListener("loaderror", (w) => { + w.url.indexOf(o()) === 0 || (h = !0), l.close(); + }), await new Promise((w, m) => { + l.addEventListener("exit", () => { + h ? m(new Error("User closed the login window.")) : (this.clearToken(), w()); + }); + }); + }, + register: async (c) => { + const a = await this.createRegisterUrl(), l = n(c), h = e(a, "_blank", l); + await new Promise((m, C) => { + h.addEventListener("loadstart", async (p) => { + if (p.url.indexOf(o()) === 0) { + h.close(); + const k = d(this, s, P).call(this, p.url); + try { + await d(this, s, z).call(this, k), m(); + } catch (g) { + C(g); + } + } + }); + }); + }, + accountManagement: async () => { + const c = this.createAccountUrl(); + if (typeof c < "u") { + const a = e(c, "_blank", "location=no"); + a.addEventListener("loadstart", function(l) { + l.url.indexOf(o()) === 0 && a.close(); + }); + } else + throw new Error("Not supported by the OIDC server"); + }, + redirectUri: () => o() + }; +}, /** + * @returns {KeycloakAdapter} + */ +Ee = function() { + return { + login: async (e) => { + const t = await this.createLoginUrl(e); + await new Promise((i, n) => { + universalLinks.subscribe("keycloak", async (o) => { + universalLinks.unsubscribe("keycloak"), window.cordova.plugins.browsertab.close(); + const c = d(this, s, P).call(this, o.url); + try { + await d(this, s, z).call(this, c), i(); + } catch (a) { + n(a); + } + }), window.cordova.plugins.browsertab.openUrl(t); + }); + }, + logout: async (e) => { + const t = this.createLogoutUrl(e); + await new Promise((i) => { + universalLinks.subscribe("keycloak", () => { + universalLinks.unsubscribe("keycloak"), window.cordova.plugins.browsertab.close(), this.clearToken(), i(); + }), window.cordova.plugins.browsertab.openUrl(t); + }); + }, + register: async (e) => { + const t = await this.createRegisterUrl(e); + await new Promise((i, n) => { + universalLinks.subscribe("keycloak", async (o) => { + universalLinks.unsubscribe("keycloak"), window.cordova.plugins.browsertab.close(); + const c = d(this, s, P).call(this, o.url); + try { + await d(this, s, z).call(this, c), i(); + } catch (a) { + n(a); + } + }), window.cordova.plugins.browsertab.openUrl(t); + }); + }, + accountManagement: async () => { + const e = this.createAccountUrl(); + if (typeof e < "u") + window.cordova.plugins.browsertab.openUrl(e); + else + throw new Error("Not supported by the OIDC server"); + }, + redirectUri: (e) => e && e.redirectUri ? e.redirectUri : this.redirectUri ? this.redirectUri : "http://localhost" + }; +}, Ae = async function() { + if (typeof u(this, L) == "string") { + const e = await nt(u(this, L)); + this.authServerUrl = e["auth-server-url"], this.realm = e.realm, this.clientId = e.resource, d(this, s, ae).call(this); + } else + this.clientId = u(this, L).clientId, "oidcProvider" in u(this, L) ? await d(this, s, Ie).call(this, u(this, L).oidcProvider) : (this.authServerUrl = u(this, L).url, this.realm = u(this, L).realm, d(this, s, ae).call(this)); +}, /** + * @returns {void} + */ +ae = function() { + this.endpoints = { + authorize: () => d(this, s, R).call(this) + "/protocol/openid-connect/auth", + token: () => d(this, s, R).call(this) + "/protocol/openid-connect/token", + logout: () => d(this, s, R).call(this) + "/protocol/openid-connect/logout", + checkSessionIframe: () => d(this, s, R).call(this) + "/protocol/openid-connect/login-status-iframe.html", + thirdPartyCookiesIframe: () => d(this, s, R).call(this) + "/protocol/openid-connect/3p-cookies/step1.html", + register: () => d(this, s, R).call(this) + "/protocol/openid-connect/registrations", + userinfo: () => d(this, s, R).call(this) + "/protocol/openid-connect/userinfo" + }; +}, Ie = async function(e) { + if (typeof e == "string") { + const t = `${Ue(e)}/.well-known/openid-configuration`, i = await st(t); + d(this, s, ce).call(this, i); + } else + d(this, s, ce).call(this, e); +}, /** + * @param {OpenIdProviderMetadata} config + * @returns {void} + */ +ce = function(e) { + this.endpoints = { + authorize() { + return e.authorization_endpoint; + }, + token() { + return e.token_endpoint; + }, + logout() { + if (!e.end_session_endpoint) + throw new Error("Not supported by the OIDC server"); + return e.end_session_endpoint; + }, + checkSessionIframe() { + if (!e.check_session_iframe) + throw new Error("Not supported by the OIDC server"); + return e.check_session_iframe; + }, + register() { + throw new Error('Redirection to "Register user" page not supported in standard OIDC mode'); + }, + userinfo() { + if (!e.userinfo_endpoint) + throw new Error("Not supported by the OIDC server"); + return e.userinfo_endpoint; + } + }; +}, xe = async function() { + if (!u(this, b).enable && !this.silentCheckSsoRedirectUri || typeof this.endpoints.thirdPartyCookiesIframe != "function") + return; + const e = document.createElement("iframe"); + e.setAttribute("src", this.endpoints.thirdPartyCookiesIframe()), e.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin"), e.setAttribute("title", "keycloak-3p-check-iframe"), e.style.display = "none", document.body.appendChild(e); + const t = new Promise((i) => { + const n = (o) => { + e.contentWindow === o.source && (o.data !== "supported" && o.data !== "unsupported" || (o.data === "unsupported" && (u(this, q).call(this, `[KEYCLOAK] Your browser is blocking access to 3rd-party cookies, this means: + + - It is not possible to retrieve tokens without redirecting to the Keycloak server (a.k.a. no support for silent authentication). + - It is not possible to automatically detect changes to the session status (such as the user logging out in another tab). + +For more information see: https://www.keycloak.org/securing-apps/javascript-adapter#_modern_browsers`), u(this, b).enable = !1, this.silentCheckSsoFallback && (this.silentCheckSsoRedirectUri = void 0)), document.body.removeChild(e), window.removeEventListener("message", n), i())); + }; + window.addEventListener("message", n, !1); + }); + return await Qe(t, this.messageReceiveTimeout, "Timeout when waiting for 3rd party check iframe message."); +}, Le = async function(e) { + var o, c, a; + const t = d(this, s, P).call(this, window.location.href); + if (t != null && t.newUrl && window.history.replaceState(window.history.state, "", t.newUrl), t && t.valid) { + await d(this, s, te).call(this), await d(this, s, z).call(this, t); + return; + } + const i = async (l) => { + const h = {}; + l || (h.prompt = "none"), e.locale && (h.locale = e.locale), await this.login(h); + }, n = async () => { + switch (e.onLoad) { + case "check-sso": + u(this, b).enable ? (await d(this, s, te).call(this), await d(this, s, X).call(this) || (this.silentCheckSsoRedirectUri ? await d(this, s, le).call(this) : await i(!1))) : this.silentCheckSsoRedirectUri ? await d(this, s, le).call(this) : await i(!1); + break; + case "login-required": + await i(!0); + break; + default: + throw new Error("Invalid value for onLoad"); + } + }; + if (e.token && e.refreshToken) + if (d(this, s, Z).call(this, e.token, e.refreshToken, e.idToken), u(this, b).enable) + await d(this, s, te).call(this), await d(this, s, X).call(this) && ((o = this.onAuthSuccess) == null || o.call(this), d(this, s, re).call(this)); + else + try { + await this.updateToken(-1), (c = this.onAuthSuccess) == null || c.call(this); + } catch (l) { + if ((a = this.onAuthError) == null || a.call(this), e.onLoad) + await n(); + else + throw l; + } + else e.onLoad && await n(); +}, te = async function() { + if (!u(this, b).enable || u(this, b).iframe) + return; + const e = document.createElement("iframe"); + u(this, b).iframe = e, e.setAttribute("src", this.endpoints.checkSessionIframe()), e.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin"), e.setAttribute("title", "keycloak-session-iframe"), e.style.display = "none", document.body.appendChild(e); + const t = (n) => { + var c; + if (n.origin !== u(this, b).iframeOrigin || ((c = u(this, b).iframe) == null ? void 0 : c.contentWindow) !== n.source || !(n.data === "unchanged" || n.data === "changed" || n.data === "error")) + return; + n.data !== "unchanged" && this.clearToken(); + const o = u(this, b).callbackList; + u(this, b).callbackList = []; + for (const a of o.reverse()) + n.data === "error" ? a(new Error("Error while checking login iframe")) : a(null, n.data === "unchanged"); + }; + window.addEventListener("message", t, !1), await new Promise((n) => { + e.addEventListener("load", () => { + const o = this.endpoints.authorize(); + o.startsWith("/") ? u(this, b).iframeOrigin = globalThis.location.origin : u(this, b).iframeOrigin = new URL(o).origin, n(); + }); + }); +}, X = async function() { + if (!u(this, b).iframe || !u(this, b).iframeOrigin) + return; + const e = `${this.clientId} ${this.sessionId ? this.sessionId : ""}`, t = u(this, b).iframeOrigin; + return await new Promise((n, o) => { + var a, l; + const c = (h, w) => h ? o(h) : n( + /** @type {boolean} */ + w + ); + u(this, b).callbackList.push(c), u(this, b).callbackList.length === 1 && ((l = (a = u(this, b).iframe) == null ? void 0 : a.contentWindow) == null || l.postMessage(e, t)); + }); +}, le = async function() { + const e = document.createElement("iframe"), t = await this.createLoginUrl({ prompt: "none", redirectUri: this.silentCheckSsoRedirectUri }); + return e.setAttribute("src", t), e.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin"), e.setAttribute("title", "keycloak-silent-check-sso"), e.style.display = "none", document.body.appendChild(e), await new Promise((i, n) => { + const o = async (c) => { + if (c.origin !== window.location.origin || e.contentWindow !== c.source) + return; + const a = d(this, s, P).call(this, c.data); + try { + await d(this, s, z).call(this, a), i(); + } catch (l) { + n(l); + } + document.body.removeChild(e), window.removeEventListener("message", o); + }; + window.addEventListener("message", o); + }); +}, /** + * @param {string} url + */ +P = function(e) { + const t = d(this, s, Re).call(this, e); + if (!t) + return; + const i = u(this, J).get(t.state); + return i && (t.valid = !0, t.redirectUri = i.redirectUri, t.storedNonce = i.nonce, t.prompt = i.prompt, t.pkceCodeVerifier = i.pkceCodeVerifier, t.loginOptions = i.loginOptions), t; +}, /** + * @param {string} urlString + */ +Re = function(e) { + let t = []; + switch (this.flow) { + case "standard": + t = ["code", "state", "session_state", "kc_action_status", "kc_action", "iss"]; + break; + case "implicit": + t = ["access_token", "token_type", "id_token", "state", "session_state", "expires_in", "kc_action_status", "kc_action", "iss"]; + break; + case "hybrid": + t = ["access_token", "token_type", "id_token", "code", "state", "session_state", "expires_in", "kc_action_status", "kc_action", "iss"]; + break; + } + t.push("error"), t.push("error_description"), t.push("error_uri"); + const i = new URL(e); + let n = "", o; + if (this.responseMode === "query" && i.searchParams.size > 0 ? (o = d(this, s, de).call(this, i.search, t), i.search = o.paramsString, n = i.toString()) : this.responseMode === "fragment" && i.hash.length > 0 && (o = d(this, s, de).call(this, i.hash.substring(1), t), i.hash = o.paramsString, n = i.toString()), o != null && o.oauthParams) { + if (this.flow === "standard" || this.flow === "hybrid") { + if ((o.oauthParams.code || o.oauthParams.error) && o.oauthParams.state) + return o.oauthParams.newUrl = n, o.oauthParams; + } else if (this.flow === "implicit" && (o.oauthParams.access_token || o.oauthParams.error) && o.oauthParams.state) + return o.oauthParams.newUrl = n, o.oauthParams; + } +}, /** + * @typedef {Object} ParsedCallbackParams + * @property {string} paramsString + * @property {Record} oauthParams + */ +/** + * @param {string} paramsString + * @param {string[]} supportedParams + * @returns {ParsedCallbackParams} + */ +de = function(e, t) { + const i = e.split("&"), n = {}; + let o = ""; + for (const c of i.reverse()) { + const a = new URLSearchParams(c).entries().next().value; + if (!a) { + o = "&" + o; + continue; + } + const [l, h] = a; + t.includes(l) && !(l in n) ? n[l] = h : o = o.length === 0 ? c : c + "&" + o; + } + return { + paramsString: o, + oauthParams: n + }; +}, z = async function(e) { + var a, l, h, w; + const { code: t, error: i, prompt: n } = e; + let o = (/* @__PURE__ */ new Date()).getTime(); + const c = (m, C, p) => { + if (o = (o + (/* @__PURE__ */ new Date()).getTime()) / 2, d(this, s, Z).call(this, m, C, p, o), u(this, $) && this.idTokenParsed && this.idTokenParsed.nonce !== e.storedNonce) + throw u(this, M).call(this, "[KEYCLOAK] Invalid nonce, clearing token"), this.clearToken(), new Error("Invalid nonce."); + }; + if (e.kc_action_status && this.onActionUpdate && this.onActionUpdate(e.kc_action_status, e.kc_action), i) { + if (n !== "none") + if (e.error_description && e.error_description === "authentication_expired") + await this.login(e.loginOptions); + else { + const m = { error: i, error_description: e.error_description }; + throw (a = this.onAuthError) == null || a.call(this, m), m; + } + return; + } else this.flow !== "standard" && (e.access_token || e.id_token) && (c(e.access_token, void 0, e.id_token), (l = this.onAuthSuccess) == null || l.call(this)); + if (this.flow !== "implicit" && t) + try { + const m = await at( + this.endpoints.token(), + t, + /** @type {string} */ + this.clientId, + e.redirectUri, + e.pkceCodeVerifier + ); + c(m.access_token, m.refresh_token, m.id_token), this.flow === "standard" && ((h = this.onAuthSuccess) == null || h.call(this)), d(this, s, re).call(this); + } catch (m) { + throw (w = this.onAuthError) == null || w.call(this), m; + } +}, re = async function() { + u(this, b).enable && this.token && (await dt(u(this, b).interval * 1e3), await d(this, s, X).call(this) && await d(this, s, re).call(this)); +}, /** + * @param {string} [token] + * @param {string} [refreshToken] + * @param {string} [idToken] + * @param {number} [timeLocal] + */ +Z = function(e, t, i, n) { + if (this.tokenTimeoutHandle && (clearTimeout(this.tokenTimeoutHandle), this.tokenTimeoutHandle = void 0), t ? (this.refreshToken = t, this.refreshTokenParsed = ne(t)) : (delete this.refreshToken, delete this.refreshTokenParsed), i ? (this.idToken = i, this.idTokenParsed = ne(i)) : (delete this.idToken, delete this.idTokenParsed), e) { + if (this.token = e, this.tokenParsed = ne(e), this.sessionId = this.tokenParsed.sid, this.authenticated = !0, this.subject = this.tokenParsed.sub, this.realmAccess = this.tokenParsed.realm_access, this.resourceAccess = this.tokenParsed.resource_access, n && (this.timeSkew = Math.floor(n / 1e3) - this.tokenParsed.iat), this.timeSkew !== null && (u(this, M).call(this, "[KEYCLOAK] Estimated time difference between browser and server is " + this.timeSkew + " seconds"), this.onTokenExpired)) { + const o = (this.tokenParsed.exp - (/* @__PURE__ */ new Date()).getTime() / 1e3 + this.timeSkew) * 1e3; + u(this, M).call(this, "[KEYCLOAK] Token expires in " + Math.round(o / 1e3) + " s"), o <= 0 ? this.onTokenExpired() : this.tokenTimeoutHandle = window.setTimeout(this.onTokenExpired, o); + } + } else + delete this.token, delete this.tokenParsed, delete this.subject, delete this.realmAccess, delete this.resourceAccess, this.authenticated = !1; +}, /** + * @returns {string=} + */ +R = function() { + if (!(typeof this.authServerUrl > "u")) + return `${Ue(this.authServerUrl)}/realms/${encodeURIComponent( + /** @type {string} */ + this.realm + )}`; +}, /** + * @param {Function} fn + * @returns {(message: string) => void} + */ +he = function(e) { + return (t) => { + this.enableLogging && e.call(console, t); + }; +}; +function Se() { + if (typeof crypto > "u" || typeof crypto.randomUUID > "u") + throw new Error("Web Crypto API is not available."); + return crypto.randomUUID(); +} +function Ye(r) { + return JSON.stringify({ + id_token: { + acr: r + } + }); +} +function $e(r) { + return qe(r, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); +} +async function Je(r, e) { + if (r !== "S256") + throw new TypeError(`Invalid value for 'pkceMethod', expected 'S256' but got '${r}'.`); + const t = new Uint8Array(await rt(e)); + return tt(t).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); +} +function qe(r, e) { + const t = Ge(r), i = new Array(r); + for (let n = 0; n < r; n++) + i[n] = e.charCodeAt(t[n] % e.length); + return String.fromCharCode.apply(null, i); +} +function Ge(r) { + if (typeof crypto > "u" || typeof crypto.getRandomValues > "u") + throw new Error("Web Crypto API is not available."); + return crypto.getRandomValues(new Uint8Array(r)); +} +function Qe(r, e, t) { + let i; + const n = new Promise(function(o, c) { + i = window.setTimeout(function() { + c(new Error(t)); + }, e); + }); + return Promise.race([r, n]).finally(function() { + clearTimeout(i); + }); +} +function Xe() { + try { + return new Ze(); + } catch { + return new et(); + } +} +const Y = "kc-callback-"; +var x, ue, Me, fe, De; +class Ze { + constructor() { + A(this, x); + globalThis.localStorage.setItem("kc-test", "test"), globalThis.localStorage.removeItem("kc-test"); + } + /** + * @param {string} [state] + * @returns {CallbackState | null} + */ + get(e) { + if (!e) + return null; + d(this, x, ue).call(this); + const t = Y + e, i = globalThis.localStorage.getItem(t); + return i ? (globalThis.localStorage.removeItem(t), JSON.parse(i)) : null; + } + /** + * @param {CallbackState} state + */ + add(e) { + d(this, x, ue).call(this); + const t = Y + e.state, i = JSON.stringify({ + ...e, + // Set the expiry time to 1 hour from now. + expires: Date.now() + 60 * 60 * 1e3 + }); + try { + globalThis.localStorage.setItem(t, i); + } catch { + d(this, x, Me).call(this), globalThis.localStorage.setItem(t, i); + } + } +} +x = new WeakSet(), /** + * Clears all values from local storage that are no longer valid. + */ +ue = function() { + const e = Date.now(); + for (const [t, i] of d(this, x, fe).call(this)) { + const n = d(this, x, De).call(this, i); + (n === null || n < e) && globalThis.localStorage.removeItem(t); + } +}, /** + * Clears all known values from local storage. + */ +Me = function() { + for (const [e] of d(this, x, fe).call(this)) + globalThis.localStorage.removeItem(e); +}, /** + * Gets all entries stored in local storage that are known to be managed by this class. + * @returns {[string, string][]} An array of key-value pairs. + */ +fe = function() { + return Object.entries(globalThis.localStorage).filter(([e]) => e.startsWith(Y)); +}, /** + * Parses the expiry time from a value stored in local storage. + * @param {string} value + * @returns {number | null} The expiry time in milliseconds, or `null` if the value is malformed. + */ +De = function(e) { + let t; + try { + t = JSON.parse(e); + } catch { + return null; + } + return me(t) && "expires" in t && typeof t.expires == "number" ? t.expires : null; +}; +var D, Ne, pe, we; +class et { + constructor() { + A(this, D); + } + /** + * @param {string} [state] + * @returns {CallbackState | null} + */ + get(e) { + if (!e) + return null; + const t = d(this, D, Ne).call(this, Y + e); + return d(this, D, pe).call(this, Y + e, "", d(this, D, we).call(this, -100)), t ? JSON.parse(t) : null; + } + /** + * @param {CallbackState} state + */ + add(e) { + d(this, D, pe).call(this, Y + e.state, JSON.stringify(e), d(this, D, we).call(this, 60)); + } +} +D = new WeakSet(), /** + * @param {string} key + * @returns + */ +Ne = function(e) { + const t = e + "=", i = document.cookie.split(";"); + for (let n = 0; n < i.length; n++) { + let o = i[n]; + for (; o.charAt(0) === " "; ) + o = o.substring(1); + if (o.indexOf(t) === 0) + return o.substring(t.length, o.length); + } + return ""; +}, /** + * @param {string} key + * @param {string} value + * @param {Date} expirationDate + */ +pe = function(e, t, i) { + const n = e + "=" + t + "; expires=" + i.toUTCString() + "; "; + document.cookie = n; +}, /** + * @param {number} minutes + * @returns {Date} + */ +we = function(e) { + const t = /* @__PURE__ */ new Date(); + return t.setTime(t.getTime() + e * 60 * 1e3), t; +}; +function tt(r) { + const e = String.fromCodePoint(...r); + return btoa(e); +} +async function rt(r) { + const t = new TextEncoder().encode(r); + if (typeof crypto > "u" || typeof crypto.subtle > "u") + throw new Error("Web Crypto API is not available."); + return await crypto.subtle.digest("SHA-256", t); +} +function ne(r) { + const [, e] = r.split("."); + if (typeof e != "string") + throw new Error("Unable to decode token, payload not found."); + let t; + try { + t = it(e); + } catch (i) { + throw new Error("Unable to decode token, payload is not a valid Base64URL value.", { cause: i }); + } + try { + return JSON.parse(t); + } catch (i) { + throw new Error("Unable to decode token, payload is not a valid JSON value.", { cause: i }); + } +} +function it(r) { + let e = r.replaceAll("-", "+").replaceAll("_", "/"); + switch (e.length % 4) { + case 0: + break; + case 2: + e += "=="; + break; + case 3: + e += "="; + break; + default: + throw new Error("Input is not of the correct length."); + } + try { + return ot(e); + } catch { + return atob(e); + } +} +function ot(r) { + return decodeURIComponent(atob(r).replace(/(.)/g, (e, t) => { + let i = t.charCodeAt(0).toString(16).toUpperCase(); + return i.length < 2 && (i = "0" + i), "%" + i; + })); +} +function me(r) { + return typeof r == "object" && r !== null; +} +async function nt(r) { + return await Q(r); +} +async function st(r) { + return await Q(r); +} +async function at(r, e, t, i, n) { + const o = new URLSearchParams([ + ["code", e], + ["grant_type", "authorization_code"], + ["client_id", t], + ["redirect_uri", i] + ]); + return n && o.append("code_verifier", n), await Q(r, { + method: "POST", + credentials: "include", + body: o + }); +} +async function ct(r, e, t) { + const i = new URLSearchParams([ + ["grant_type", "refresh_token"], + ["refresh_token", e], + ["client_id", t] + ]); + return await Q(r, { + method: "POST", + credentials: "include", + body: i + }); +} +async function Q(r, e = {}) { + const t = new Headers(e.headers); + return t.set("Accept", Ve), await (await lt(r, { + ...e, + headers: t + })).json(); +} +async function lt(r, e) { + const t = await fetch(r, e); + if (!t.ok) + throw new Ke("Server responded with an invalid status.", { response: t }); + return t; +} +function Ce(r) { + if (!r) + throw new Error("Unable to build authorization header, token is not set, make sure the user is authenticated."); + return ["Authorization", `bearer ${r}`]; +} +function Ue(r) { + return r.endsWith("/") ? r.slice(0, -1) : r; +} +class Ke extends Error { + /** + * @param {string} message + * @param {NetworkErrorOptions} options + */ + constructor(t, i) { + super(t, i); + /** @type {Response} */ + f(this, "response"); + this.response = i.response; + } +} +const dt = (r) => new Promise((e) => setTimeout(e, r)), ht = "https://auth.ibagher.ir", ut = "bi"; +let _ = null, se = null; +const Be = Oe(null), ft = (r) => (_ || (_ = new He({ + url: ht, + realm: ut, + clientId: r +})), _), pt = ({ clientId: r, initOptions: e = {} }) => { + const t = ft(r); + return se || (se = t.init({ + onLoad: "login-required", + checkLoginIframe: !1, + flow: "implicit", + ...e + })), se; +}, Ut = ({ + children: r, + clientId: e, + initOptions: t, + loading: i = null +}) => { + const [n, o] = I(!1), [c, a] = I(!1), [l, h] = I(null), w = ie(!1), m = H(() => { + _ && (a(!!_.authenticated), h(_.token ?? null)); + }, []); + W(() => (w.current = !0, pt({ clientId: e, initOptions: t }).then((S) => { + w.current && (a(!!S), h((_ == null ? void 0 : _.token) ?? null), o(!0)); + }).catch(() => { + w.current && (a(!1), h(null), o(!0)); + }), () => { + w.current = !1; + }), [e, t]); + const C = H(() => _ == null ? void 0 : _.login(), []), p = H((S) => _ == null ? void 0 : _.logout(S), []), k = H( + async (S = 30) => { + if (!_) return !1; + const V = await _.updateToken(S); + return m(), V; + }, + [m] + ), g = We( + () => ({ + initialized: n, + authenticated: c, + token: l, + login: C, + logout: p, + updateToken: k + }), + [n, c, l, C, p, k] + ); + return n ? /* @__PURE__ */ v(Be.Provider, { value: g, children: r }) : i; +}, _t = () => { + const r = Fe(Be); + if (!r) + throw new Error("useKeycloak must be used inside KeycloakProvider"); + return r; }; export { - O as LightPagination, - L as Pagination, - H as SimplePagination, - D as toEnDigits, - t as toFaDigits, - K as toFaNumber + Ut as KeycloakProvider, + vt as LightPagination, + St as Pagination, + Ct as SimplePagination, + pt as initKeycloak, + F as toEnDigits, + y as toFaDigits, + yt as toFaNumber, + _t as useKeycloak }; diff --git a/package.json b/package.json index fc8bc10..2e100de 100644 --- a/package.json +++ b/package.json @@ -19,5 +19,8 @@ "devDependencies": { "@vitejs/plugin-react": "4.3.4", "vite": "5.4.19" + }, + "dependencies": { + "keycloak-js": "^26.2.4" } } diff --git a/src/core/keycloak.jsx b/src/core/keycloak.jsx new file mode 100644 index 0000000..7169b47 --- /dev/null +++ b/src/core/keycloak.jsx @@ -0,0 +1,139 @@ +import Keycloak from "keycloak-js"; +import { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useRef, + useState, +} from "react"; + +const KEYCLOAK_URL = "https://auth.ibagher.ir"; +const KEYCLOAK_REALM = "bi"; + +let keycloakInstance = null; +let initPromise = null; + +const KeycloakContext = createContext(null); + +const createKeycloak = (clientId) => { + if (!keycloakInstance) { + keycloakInstance = new Keycloak({ + url: KEYCLOAK_URL, + realm: KEYCLOAK_REALM, + clientId, + }); + } + + return keycloakInstance; +}; + +export const initKeycloak = ({ clientId, initOptions = {} }) => { + const keycloak = createKeycloak(clientId); + + if (!initPromise) { + initPromise = keycloak.init({ + onLoad: "login-required", + checkLoginIframe: false, + flow: "implicit", + ...initOptions, + }); + } + + return initPromise; +}; + +export const KeycloakProvider = ({ + children, + clientId, + initOptions, + loading = null, +}) => { + const [initialized, setInitialized] = useState(false); + const [authenticated, setAuthenticated] = useState(false); + const [token, setToken] = useState(null); + const mountedRef = useRef(false); + + const syncState = useCallback(() => { + if (!keycloakInstance) return; + + setAuthenticated(Boolean(keycloakInstance.authenticated)); + setToken(keycloakInstance.token ?? null); + }, []); + + useEffect(() => { + mountedRef.current = true; + + initKeycloak({ clientId, initOptions }) + .then((auth) => { + if (!mountedRef.current) return; + + setAuthenticated(Boolean(auth)); + setToken(keycloakInstance?.token ?? null); + setInitialized(true); + }) + .catch(() => { + if (!mountedRef.current) return; + + setAuthenticated(false); + setToken(null); + setInitialized(true); + }); + + return () => { + mountedRef.current = false; + }; + }, [clientId, initOptions]); + + const login = useCallback(() => { + return keycloakInstance?.login(); + }, []); + + const logout = useCallback((options) => { + return keycloakInstance?.logout(options); + }, []); + + const updateToken = useCallback( + async (minValidity = 30) => { + if (!keycloakInstance) return false; + + const refreshed = await keycloakInstance.updateToken(minValidity); + + syncState(); + + return refreshed; + }, + [syncState], + ); + + const value = useMemo( + () => ({ + initialized, + authenticated, + token, + login, + logout, + updateToken, + }), + [initialized, authenticated, token, login, logout, updateToken], + ); + + if (!initialized) return loading; + + return ( + + {children} + + ); +}; + +export const useKeycloak = () => { + const context = useContext(KeycloakContext); + + if (!context) { + throw new Error("useKeycloak must be used inside KeycloakProvider"); + } + + return context; +}; \ No newline at end of file diff --git a/src/index.js b/src/index.js index 06b64ec..a96a43b 100644 --- a/src/index.js +++ b/src/index.js @@ -3,3 +3,9 @@ export { toFaNumber, toFaDigits, toEnDigits } from "./utils/numbers.js"; export { LightPagination } from "./components/pagination/LightPagination.jsx"; export { Pagination } from "./components/pagination/Pagination.jsx"; export { SimplePagination } from "./components/pagination/SimplePagination.jsx"; + +export { + KeycloakProvider, + useKeycloak, + initKeycloak, +} from "./core/keycloak.jsx"; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 5c9ba7d..8d8d640 100644 --- a/yarn.lock +++ b/yarn.lock @@ -580,6 +580,11 @@ json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +keycloak-js@^26.2.4: + version "26.2.4" + resolved "https://registry.yarnpkg.com/keycloak-js/-/keycloak-js-26.2.4.tgz#b96ff33ed08ff6fd8d1e09d9e5055c7b3f2fa918" + integrity sha512-PnXpR3ubETGOt0B/Qt2lxmPbkZr5bc3vlQsOqDoTPPQsZRp7JjhTKxlJ187uWh8qJhvBab6Gsjb06a8ayOPfuw== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"