@chemmangat/msal-next 4.1.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +85 -0
- package/dist/index.d.mts +258 -1
- package/dist/index.d.ts +258 -1
- package/dist/index.js +705 -34
- package/dist/index.mjs +700 -32
- package/package.json +26 -4
package/dist/index.mjs
CHANGED
|
@@ -1686,8 +1686,673 @@ var ErrorBoundary = class extends Component {
|
|
|
1686
1686
|
}
|
|
1687
1687
|
};
|
|
1688
1688
|
|
|
1689
|
+
// src/hooks/useMultiAccount.ts
|
|
1690
|
+
import { useMsal as useMsal2 } from "@azure/msal-react";
|
|
1691
|
+
import { InteractionStatus as InteractionStatus2 } from "@azure/msal-browser";
|
|
1692
|
+
import { useCallback as useCallback5, useMemo as useMemo2, useState as useState5, useEffect as useEffect7 } from "react";
|
|
1693
|
+
function useMultiAccount(defaultScopes = ["User.Read"]) {
|
|
1694
|
+
const { instance, accounts, inProgress } = useMsal2();
|
|
1695
|
+
const [activeAccount, setActiveAccount] = useState5(
|
|
1696
|
+
instance.getActiveAccount()
|
|
1697
|
+
);
|
|
1698
|
+
useEffect7(() => {
|
|
1699
|
+
const currentActive = instance.getActiveAccount();
|
|
1700
|
+
if (currentActive?.homeAccountId !== activeAccount?.homeAccountId) {
|
|
1701
|
+
setActiveAccount(currentActive);
|
|
1702
|
+
}
|
|
1703
|
+
}, [instance, accounts, activeAccount]);
|
|
1704
|
+
const hasMultipleAccounts = useMemo2(() => accounts.length > 1, [accounts]);
|
|
1705
|
+
const accountCount = useMemo2(() => accounts.length, [accounts]);
|
|
1706
|
+
const switchAccount = useCallback5(
|
|
1707
|
+
(account) => {
|
|
1708
|
+
try {
|
|
1709
|
+
instance.setActiveAccount(account);
|
|
1710
|
+
setActiveAccount(account);
|
|
1711
|
+
if (process.env.NODE_ENV === "development") {
|
|
1712
|
+
console.log("[MSAL Multi-Account] Switched to account:", account.username);
|
|
1713
|
+
}
|
|
1714
|
+
} catch (error) {
|
|
1715
|
+
const msalError = wrapMsalError(error);
|
|
1716
|
+
console.error("[MSAL Multi-Account] Failed to switch account:", msalError.message);
|
|
1717
|
+
throw msalError;
|
|
1718
|
+
}
|
|
1719
|
+
},
|
|
1720
|
+
[instance]
|
|
1721
|
+
);
|
|
1722
|
+
const addAccount = useCallback5(
|
|
1723
|
+
async (scopes = defaultScopes) => {
|
|
1724
|
+
if (inProgress !== InteractionStatus2.None) {
|
|
1725
|
+
console.warn("[MSAL Multi-Account] Interaction already in progress");
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
try {
|
|
1729
|
+
const request = {
|
|
1730
|
+
scopes,
|
|
1731
|
+
prompt: "select_account",
|
|
1732
|
+
// Force account selection
|
|
1733
|
+
loginHint: void 0
|
|
1734
|
+
// Don't hint any account
|
|
1735
|
+
};
|
|
1736
|
+
await instance.loginRedirect(request);
|
|
1737
|
+
} catch (error) {
|
|
1738
|
+
const msalError = wrapMsalError(error);
|
|
1739
|
+
if (msalError.isUserCancellation()) {
|
|
1740
|
+
console.log("[MSAL Multi-Account] User cancelled adding account");
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
if (process.env.NODE_ENV === "development") {
|
|
1744
|
+
console.error(msalError.toConsoleString());
|
|
1745
|
+
} else {
|
|
1746
|
+
console.error("[MSAL Multi-Account] Failed to add account:", msalError.message);
|
|
1747
|
+
}
|
|
1748
|
+
throw msalError;
|
|
1749
|
+
}
|
|
1750
|
+
},
|
|
1751
|
+
[instance, defaultScopes, inProgress]
|
|
1752
|
+
);
|
|
1753
|
+
const removeAccount = useCallback5(
|
|
1754
|
+
async (account) => {
|
|
1755
|
+
try {
|
|
1756
|
+
if (activeAccount?.homeAccountId === account.homeAccountId) {
|
|
1757
|
+
const otherAccounts = accounts.filter(
|
|
1758
|
+
(acc) => acc.homeAccountId !== account.homeAccountId
|
|
1759
|
+
);
|
|
1760
|
+
if (otherAccounts.length > 0) {
|
|
1761
|
+
instance.setActiveAccount(otherAccounts[0]);
|
|
1762
|
+
setActiveAccount(otherAccounts[0]);
|
|
1763
|
+
} else {
|
|
1764
|
+
instance.setActiveAccount(null);
|
|
1765
|
+
setActiveAccount(null);
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
await instance.clearCache({
|
|
1769
|
+
account
|
|
1770
|
+
});
|
|
1771
|
+
if (process.env.NODE_ENV === "development") {
|
|
1772
|
+
console.log("[MSAL Multi-Account] Removed account:", account.username);
|
|
1773
|
+
}
|
|
1774
|
+
} catch (error) {
|
|
1775
|
+
const msalError = wrapMsalError(error);
|
|
1776
|
+
console.error("[MSAL Multi-Account] Failed to remove account:", msalError.message);
|
|
1777
|
+
throw msalError;
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1780
|
+
[instance, activeAccount, accounts]
|
|
1781
|
+
);
|
|
1782
|
+
const signOutAccount = useCallback5(
|
|
1783
|
+
async (account) => {
|
|
1784
|
+
try {
|
|
1785
|
+
await instance.logoutRedirect({
|
|
1786
|
+
account
|
|
1787
|
+
});
|
|
1788
|
+
} catch (error) {
|
|
1789
|
+
const msalError = wrapMsalError(error);
|
|
1790
|
+
console.error("[MSAL Multi-Account] Failed to sign out account:", msalError.message);
|
|
1791
|
+
throw msalError;
|
|
1792
|
+
}
|
|
1793
|
+
},
|
|
1794
|
+
[instance]
|
|
1795
|
+
);
|
|
1796
|
+
const signOutAll = useCallback5(async () => {
|
|
1797
|
+
try {
|
|
1798
|
+
await instance.logoutRedirect({
|
|
1799
|
+
account: activeAccount || void 0
|
|
1800
|
+
});
|
|
1801
|
+
instance.setActiveAccount(null);
|
|
1802
|
+
await instance.clearCache();
|
|
1803
|
+
} catch (error) {
|
|
1804
|
+
const msalError = wrapMsalError(error);
|
|
1805
|
+
console.error("[MSAL Multi-Account] Failed to sign out all accounts:", msalError.message);
|
|
1806
|
+
throw msalError;
|
|
1807
|
+
}
|
|
1808
|
+
}, [instance, activeAccount]);
|
|
1809
|
+
const getAccountByUsername = useCallback5(
|
|
1810
|
+
(username) => {
|
|
1811
|
+
return accounts.find((acc) => acc.username === username);
|
|
1812
|
+
},
|
|
1813
|
+
[accounts]
|
|
1814
|
+
);
|
|
1815
|
+
const getAccountById = useCallback5(
|
|
1816
|
+
(homeAccountId) => {
|
|
1817
|
+
return accounts.find((acc) => acc.homeAccountId === homeAccountId);
|
|
1818
|
+
},
|
|
1819
|
+
[accounts]
|
|
1820
|
+
);
|
|
1821
|
+
const isActiveAccount = useCallback5(
|
|
1822
|
+
(account) => {
|
|
1823
|
+
return activeAccount?.homeAccountId === account.homeAccountId;
|
|
1824
|
+
},
|
|
1825
|
+
[activeAccount]
|
|
1826
|
+
);
|
|
1827
|
+
return {
|
|
1828
|
+
accounts,
|
|
1829
|
+
activeAccount,
|
|
1830
|
+
hasMultipleAccounts,
|
|
1831
|
+
accountCount,
|
|
1832
|
+
inProgress: inProgress !== InteractionStatus2.None,
|
|
1833
|
+
switchAccount,
|
|
1834
|
+
addAccount,
|
|
1835
|
+
removeAccount,
|
|
1836
|
+
signOutAccount,
|
|
1837
|
+
signOutAll,
|
|
1838
|
+
getAccountByUsername,
|
|
1839
|
+
getAccountById,
|
|
1840
|
+
isActiveAccount
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
// src/components/AccountSwitcher.tsx
|
|
1845
|
+
import { useState as useState6 } from "react";
|
|
1846
|
+
import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1847
|
+
function AccountSwitcher({
|
|
1848
|
+
showAvatars = true,
|
|
1849
|
+
maxAccounts = 5,
|
|
1850
|
+
onSwitch,
|
|
1851
|
+
onAdd,
|
|
1852
|
+
onRemove,
|
|
1853
|
+
className = "",
|
|
1854
|
+
style,
|
|
1855
|
+
variant = "default",
|
|
1856
|
+
showAddButton = true,
|
|
1857
|
+
showRemoveButton = true
|
|
1858
|
+
}) {
|
|
1859
|
+
const {
|
|
1860
|
+
accounts,
|
|
1861
|
+
activeAccount,
|
|
1862
|
+
switchAccount,
|
|
1863
|
+
addAccount,
|
|
1864
|
+
removeAccount,
|
|
1865
|
+
isActiveAccount,
|
|
1866
|
+
accountCount
|
|
1867
|
+
} = useMultiAccount();
|
|
1868
|
+
const [isOpen, setIsOpen] = useState6(false);
|
|
1869
|
+
const [removingAccount, setRemovingAccount] = useState6(null);
|
|
1870
|
+
const handleSwitch = (account) => {
|
|
1871
|
+
switchAccount(account);
|
|
1872
|
+
setIsOpen(false);
|
|
1873
|
+
onSwitch?.(account);
|
|
1874
|
+
};
|
|
1875
|
+
const handleAdd = async () => {
|
|
1876
|
+
if (accountCount >= maxAccounts) {
|
|
1877
|
+
alert(`Maximum ${maxAccounts} accounts allowed`);
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
1880
|
+
await addAccount();
|
|
1881
|
+
onAdd?.();
|
|
1882
|
+
};
|
|
1883
|
+
const handleRemove = async (account, e) => {
|
|
1884
|
+
e.stopPropagation();
|
|
1885
|
+
if (!confirm(`Remove account ${account.username}?`)) {
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
setRemovingAccount(account.homeAccountId);
|
|
1889
|
+
try {
|
|
1890
|
+
await removeAccount(account);
|
|
1891
|
+
onRemove?.(account);
|
|
1892
|
+
} finally {
|
|
1893
|
+
setRemovingAccount(null);
|
|
1894
|
+
}
|
|
1895
|
+
};
|
|
1896
|
+
const containerStyle = {
|
|
1897
|
+
position: "relative",
|
|
1898
|
+
display: "inline-block",
|
|
1899
|
+
...style
|
|
1900
|
+
};
|
|
1901
|
+
const buttonStyle = {
|
|
1902
|
+
display: "flex",
|
|
1903
|
+
alignItems: "center",
|
|
1904
|
+
gap: "8px",
|
|
1905
|
+
padding: variant === "compact" ? "6px 12px" : "8px 16px",
|
|
1906
|
+
backgroundColor: "#fff",
|
|
1907
|
+
border: "1px solid #d1d5db",
|
|
1908
|
+
borderRadius: "6px",
|
|
1909
|
+
cursor: "pointer",
|
|
1910
|
+
fontSize: variant === "compact" ? "13px" : "14px",
|
|
1911
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
1912
|
+
};
|
|
1913
|
+
const dropdownStyle = {
|
|
1914
|
+
position: "absolute",
|
|
1915
|
+
top: "100%",
|
|
1916
|
+
right: 0,
|
|
1917
|
+
marginTop: "4px",
|
|
1918
|
+
backgroundColor: "#fff",
|
|
1919
|
+
border: "1px solid #d1d5db",
|
|
1920
|
+
borderRadius: "8px",
|
|
1921
|
+
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
|
|
1922
|
+
minWidth: variant === "minimal" ? "200px" : "280px",
|
|
1923
|
+
maxWidth: "320px",
|
|
1924
|
+
zIndex: 1e3,
|
|
1925
|
+
overflow: "hidden"
|
|
1926
|
+
};
|
|
1927
|
+
const accountItemStyle = {
|
|
1928
|
+
display: "flex",
|
|
1929
|
+
alignItems: "center",
|
|
1930
|
+
gap: "12px",
|
|
1931
|
+
padding: "12px 16px",
|
|
1932
|
+
cursor: "pointer",
|
|
1933
|
+
borderBottom: "1px solid #f3f4f6",
|
|
1934
|
+
transition: "background-color 0.15s"
|
|
1935
|
+
};
|
|
1936
|
+
const avatarStyle = {
|
|
1937
|
+
width: variant === "compact" ? "28px" : "32px",
|
|
1938
|
+
height: variant === "compact" ? "28px" : "32px",
|
|
1939
|
+
borderRadius: "50%",
|
|
1940
|
+
backgroundColor: "#3b82f6",
|
|
1941
|
+
color: "#fff",
|
|
1942
|
+
display: "flex",
|
|
1943
|
+
alignItems: "center",
|
|
1944
|
+
justifyContent: "center",
|
|
1945
|
+
fontSize: variant === "compact" ? "12px" : "14px",
|
|
1946
|
+
fontWeight: "600",
|
|
1947
|
+
flexShrink: 0
|
|
1948
|
+
};
|
|
1949
|
+
const getInitials = (name) => {
|
|
1950
|
+
if (!name) return "?";
|
|
1951
|
+
const parts = name.split(" ");
|
|
1952
|
+
if (parts.length >= 2) {
|
|
1953
|
+
return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
|
|
1954
|
+
}
|
|
1955
|
+
return name.substring(0, 2).toUpperCase();
|
|
1956
|
+
};
|
|
1957
|
+
if (!activeAccount) {
|
|
1958
|
+
return null;
|
|
1959
|
+
}
|
|
1960
|
+
return /* @__PURE__ */ jsxs6("div", { className, style: containerStyle, children: [
|
|
1961
|
+
/* @__PURE__ */ jsxs6(
|
|
1962
|
+
"button",
|
|
1963
|
+
{
|
|
1964
|
+
onClick: () => setIsOpen(!isOpen),
|
|
1965
|
+
style: buttonStyle,
|
|
1966
|
+
onMouseEnter: (e) => {
|
|
1967
|
+
e.currentTarget.style.backgroundColor = "#f9fafb";
|
|
1968
|
+
},
|
|
1969
|
+
onMouseLeave: (e) => {
|
|
1970
|
+
e.currentTarget.style.backgroundColor = "#fff";
|
|
1971
|
+
},
|
|
1972
|
+
children: [
|
|
1973
|
+
showAvatars && /* @__PURE__ */ jsx9("div", { style: avatarStyle, children: getInitials(activeAccount.name) }),
|
|
1974
|
+
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-start" }, children: [
|
|
1975
|
+
/* @__PURE__ */ jsx9("div", { style: { fontWeight: "500" }, children: activeAccount.name || activeAccount.username }),
|
|
1976
|
+
variant !== "minimal" && /* @__PURE__ */ jsx9("div", { style: { fontSize: "12px", color: "#6b7280" }, children: activeAccount.username })
|
|
1977
|
+
] }),
|
|
1978
|
+
/* @__PURE__ */ jsx9(
|
|
1979
|
+
"svg",
|
|
1980
|
+
{
|
|
1981
|
+
width: "16",
|
|
1982
|
+
height: "16",
|
|
1983
|
+
viewBox: "0 0 16 16",
|
|
1984
|
+
fill: "none",
|
|
1985
|
+
style: {
|
|
1986
|
+
marginLeft: "auto",
|
|
1987
|
+
transform: isOpen ? "rotate(180deg)" : "rotate(0deg)",
|
|
1988
|
+
transition: "transform 0.2s"
|
|
1989
|
+
},
|
|
1990
|
+
children: /* @__PURE__ */ jsx9(
|
|
1991
|
+
"path",
|
|
1992
|
+
{
|
|
1993
|
+
d: "M4 6L8 10L12 6",
|
|
1994
|
+
stroke: "currentColor",
|
|
1995
|
+
strokeWidth: "2",
|
|
1996
|
+
strokeLinecap: "round",
|
|
1997
|
+
strokeLinejoin: "round"
|
|
1998
|
+
}
|
|
1999
|
+
)
|
|
2000
|
+
}
|
|
2001
|
+
)
|
|
2002
|
+
]
|
|
2003
|
+
}
|
|
2004
|
+
),
|
|
2005
|
+
isOpen && /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
2006
|
+
/* @__PURE__ */ jsx9(
|
|
2007
|
+
"div",
|
|
2008
|
+
{
|
|
2009
|
+
style: {
|
|
2010
|
+
position: "fixed",
|
|
2011
|
+
top: 0,
|
|
2012
|
+
left: 0,
|
|
2013
|
+
right: 0,
|
|
2014
|
+
bottom: 0,
|
|
2015
|
+
zIndex: 999
|
|
2016
|
+
},
|
|
2017
|
+
onClick: () => setIsOpen(false)
|
|
2018
|
+
}
|
|
2019
|
+
),
|
|
2020
|
+
/* @__PURE__ */ jsxs6("div", { style: dropdownStyle, children: [
|
|
2021
|
+
accounts.map((account) => /* @__PURE__ */ jsxs6(
|
|
2022
|
+
"div",
|
|
2023
|
+
{
|
|
2024
|
+
onClick: () => handleSwitch(account),
|
|
2025
|
+
style: {
|
|
2026
|
+
...accountItemStyle,
|
|
2027
|
+
backgroundColor: isActiveAccount(account) ? "#eff6ff" : "#fff"
|
|
2028
|
+
},
|
|
2029
|
+
onMouseEnter: (e) => {
|
|
2030
|
+
if (!isActiveAccount(account)) {
|
|
2031
|
+
e.currentTarget.style.backgroundColor = "#f9fafb";
|
|
2032
|
+
}
|
|
2033
|
+
},
|
|
2034
|
+
onMouseLeave: (e) => {
|
|
2035
|
+
if (!isActiveAccount(account)) {
|
|
2036
|
+
e.currentTarget.style.backgroundColor = "#fff";
|
|
2037
|
+
}
|
|
2038
|
+
},
|
|
2039
|
+
children: [
|
|
2040
|
+
showAvatars && /* @__PURE__ */ jsx9("div", { style: avatarStyle, children: getInitials(account.name) }),
|
|
2041
|
+
/* @__PURE__ */ jsxs6("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
2042
|
+
/* @__PURE__ */ jsx9("div", { style: { fontWeight: "500", fontSize: "14px" }, children: account.name || account.username }),
|
|
2043
|
+
/* @__PURE__ */ jsx9(
|
|
2044
|
+
"div",
|
|
2045
|
+
{
|
|
2046
|
+
style: {
|
|
2047
|
+
fontSize: "12px",
|
|
2048
|
+
color: "#6b7280",
|
|
2049
|
+
overflow: "hidden",
|
|
2050
|
+
textOverflow: "ellipsis",
|
|
2051
|
+
whiteSpace: "nowrap"
|
|
2052
|
+
},
|
|
2053
|
+
children: account.username
|
|
2054
|
+
}
|
|
2055
|
+
)
|
|
2056
|
+
] }),
|
|
2057
|
+
isActiveAccount(account) && /* @__PURE__ */ jsx9(
|
|
2058
|
+
"svg",
|
|
2059
|
+
{
|
|
2060
|
+
width: "20",
|
|
2061
|
+
height: "20",
|
|
2062
|
+
viewBox: "0 0 20 20",
|
|
2063
|
+
fill: "none",
|
|
2064
|
+
style: { flexShrink: 0 },
|
|
2065
|
+
children: /* @__PURE__ */ jsx9(
|
|
2066
|
+
"path",
|
|
2067
|
+
{
|
|
2068
|
+
d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",
|
|
2069
|
+
fill: "#3b82f6"
|
|
2070
|
+
}
|
|
2071
|
+
)
|
|
2072
|
+
}
|
|
2073
|
+
),
|
|
2074
|
+
showRemoveButton && accounts.length > 1 && /* @__PURE__ */ jsx9(
|
|
2075
|
+
"button",
|
|
2076
|
+
{
|
|
2077
|
+
onClick: (e) => handleRemove(account, e),
|
|
2078
|
+
disabled: removingAccount === account.homeAccountId,
|
|
2079
|
+
style: {
|
|
2080
|
+
padding: "4px",
|
|
2081
|
+
backgroundColor: "transparent",
|
|
2082
|
+
border: "none",
|
|
2083
|
+
cursor: "pointer",
|
|
2084
|
+
borderRadius: "4px",
|
|
2085
|
+
display: "flex",
|
|
2086
|
+
alignItems: "center",
|
|
2087
|
+
justifyContent: "center",
|
|
2088
|
+
opacity: removingAccount === account.homeAccountId ? 0.5 : 1
|
|
2089
|
+
},
|
|
2090
|
+
onMouseEnter: (e) => {
|
|
2091
|
+
e.currentTarget.style.backgroundColor = "#fee2e2";
|
|
2092
|
+
},
|
|
2093
|
+
onMouseLeave: (e) => {
|
|
2094
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
2095
|
+
},
|
|
2096
|
+
children: /* @__PURE__ */ jsx9("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx9(
|
|
2097
|
+
"path",
|
|
2098
|
+
{
|
|
2099
|
+
d: "M4 4L12 12M12 4L4 12",
|
|
2100
|
+
stroke: "#ef4444",
|
|
2101
|
+
strokeWidth: "2",
|
|
2102
|
+
strokeLinecap: "round"
|
|
2103
|
+
}
|
|
2104
|
+
) })
|
|
2105
|
+
}
|
|
2106
|
+
)
|
|
2107
|
+
]
|
|
2108
|
+
},
|
|
2109
|
+
account.homeAccountId
|
|
2110
|
+
)),
|
|
2111
|
+
showAddButton && accountCount < maxAccounts && /* @__PURE__ */ jsxs6(
|
|
2112
|
+
"button",
|
|
2113
|
+
{
|
|
2114
|
+
onClick: handleAdd,
|
|
2115
|
+
style: {
|
|
2116
|
+
width: "100%",
|
|
2117
|
+
padding: "12px 16px",
|
|
2118
|
+
backgroundColor: "#fff",
|
|
2119
|
+
border: "none",
|
|
2120
|
+
borderTop: "1px solid #e5e7eb",
|
|
2121
|
+
cursor: "pointer",
|
|
2122
|
+
fontSize: "14px",
|
|
2123
|
+
fontWeight: "500",
|
|
2124
|
+
color: "#3b82f6",
|
|
2125
|
+
display: "flex",
|
|
2126
|
+
alignItems: "center",
|
|
2127
|
+
gap: "8px",
|
|
2128
|
+
justifyContent: "center"
|
|
2129
|
+
},
|
|
2130
|
+
onMouseEnter: (e) => {
|
|
2131
|
+
e.currentTarget.style.backgroundColor = "#f9fafb";
|
|
2132
|
+
},
|
|
2133
|
+
onMouseLeave: (e) => {
|
|
2134
|
+
e.currentTarget.style.backgroundColor = "#fff";
|
|
2135
|
+
},
|
|
2136
|
+
children: [
|
|
2137
|
+
/* @__PURE__ */ jsx9("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx9(
|
|
2138
|
+
"path",
|
|
2139
|
+
{
|
|
2140
|
+
d: "M8 3V13M3 8H13",
|
|
2141
|
+
stroke: "currentColor",
|
|
2142
|
+
strokeWidth: "2",
|
|
2143
|
+
strokeLinecap: "round"
|
|
2144
|
+
}
|
|
2145
|
+
) }),
|
|
2146
|
+
"Add Another Account"
|
|
2147
|
+
]
|
|
2148
|
+
}
|
|
2149
|
+
),
|
|
2150
|
+
accountCount >= maxAccounts && /* @__PURE__ */ jsxs6(
|
|
2151
|
+
"div",
|
|
2152
|
+
{
|
|
2153
|
+
style: {
|
|
2154
|
+
padding: "8px 16px",
|
|
2155
|
+
fontSize: "12px",
|
|
2156
|
+
color: "#6b7280",
|
|
2157
|
+
textAlign: "center",
|
|
2158
|
+
borderTop: "1px solid #e5e7eb"
|
|
2159
|
+
},
|
|
2160
|
+
children: [
|
|
2161
|
+
"Maximum ",
|
|
2162
|
+
maxAccounts,
|
|
2163
|
+
" accounts reached"
|
|
2164
|
+
]
|
|
2165
|
+
}
|
|
2166
|
+
)
|
|
2167
|
+
] })
|
|
2168
|
+
] })
|
|
2169
|
+
] });
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
// src/components/AccountList.tsx
|
|
2173
|
+
import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2174
|
+
function AccountList({
|
|
2175
|
+
showAvatars = true,
|
|
2176
|
+
showDetails = true,
|
|
2177
|
+
showActiveIndicator = true,
|
|
2178
|
+
clickToSwitch = true,
|
|
2179
|
+
onAccountClick,
|
|
2180
|
+
className = "",
|
|
2181
|
+
style,
|
|
2182
|
+
orientation = "vertical"
|
|
2183
|
+
}) {
|
|
2184
|
+
const { accounts, switchAccount, isActiveAccount } = useMultiAccount();
|
|
2185
|
+
const handleAccountClick = (account) => {
|
|
2186
|
+
if (clickToSwitch && !isActiveAccount(account)) {
|
|
2187
|
+
switchAccount(account);
|
|
2188
|
+
}
|
|
2189
|
+
onAccountClick?.(account);
|
|
2190
|
+
};
|
|
2191
|
+
const getInitials = (name) => {
|
|
2192
|
+
if (!name) return "?";
|
|
2193
|
+
const parts = name.split(" ");
|
|
2194
|
+
if (parts.length >= 2) {
|
|
2195
|
+
return `${parts[0][0]}${parts[1][0]}`.toUpperCase();
|
|
2196
|
+
}
|
|
2197
|
+
return name.substring(0, 2).toUpperCase();
|
|
2198
|
+
};
|
|
2199
|
+
const containerStyle = {
|
|
2200
|
+
display: "flex",
|
|
2201
|
+
flexDirection: orientation === "vertical" ? "column" : "row",
|
|
2202
|
+
gap: orientation === "vertical" ? "12px" : "16px",
|
|
2203
|
+
...style
|
|
2204
|
+
};
|
|
2205
|
+
const accountItemStyle = {
|
|
2206
|
+
display: "flex",
|
|
2207
|
+
alignItems: "center",
|
|
2208
|
+
gap: "12px",
|
|
2209
|
+
padding: "16px",
|
|
2210
|
+
backgroundColor: "#fff",
|
|
2211
|
+
border: "1px solid #e5e7eb",
|
|
2212
|
+
borderRadius: "8px",
|
|
2213
|
+
cursor: clickToSwitch ? "pointer" : "default",
|
|
2214
|
+
transition: "all 0.15s",
|
|
2215
|
+
position: "relative"
|
|
2216
|
+
};
|
|
2217
|
+
const avatarStyle = {
|
|
2218
|
+
width: "48px",
|
|
2219
|
+
height: "48px",
|
|
2220
|
+
borderRadius: "50%",
|
|
2221
|
+
backgroundColor: "#3b82f6",
|
|
2222
|
+
color: "#fff",
|
|
2223
|
+
display: "flex",
|
|
2224
|
+
alignItems: "center",
|
|
2225
|
+
justifyContent: "center",
|
|
2226
|
+
fontSize: "18px",
|
|
2227
|
+
fontWeight: "600",
|
|
2228
|
+
flexShrink: 0
|
|
2229
|
+
};
|
|
2230
|
+
if (accounts.length === 0) {
|
|
2231
|
+
return /* @__PURE__ */ jsx10(
|
|
2232
|
+
"div",
|
|
2233
|
+
{
|
|
2234
|
+
className,
|
|
2235
|
+
style: {
|
|
2236
|
+
padding: "24px",
|
|
2237
|
+
textAlign: "center",
|
|
2238
|
+
color: "#6b7280",
|
|
2239
|
+
backgroundColor: "#f9fafb",
|
|
2240
|
+
borderRadius: "8px",
|
|
2241
|
+
...style
|
|
2242
|
+
},
|
|
2243
|
+
children: "No accounts signed in"
|
|
2244
|
+
}
|
|
2245
|
+
);
|
|
2246
|
+
}
|
|
2247
|
+
return /* @__PURE__ */ jsx10("div", { className, style: containerStyle, children: accounts.map((account) => {
|
|
2248
|
+
const isActive = isActiveAccount(account);
|
|
2249
|
+
return /* @__PURE__ */ jsxs7(
|
|
2250
|
+
"div",
|
|
2251
|
+
{
|
|
2252
|
+
onClick: () => handleAccountClick(account),
|
|
2253
|
+
style: {
|
|
2254
|
+
...accountItemStyle,
|
|
2255
|
+
borderColor: isActive ? "#3b82f6" : "#e5e7eb",
|
|
2256
|
+
backgroundColor: isActive ? "#eff6ff" : "#fff",
|
|
2257
|
+
boxShadow: isActive ? "0 0 0 3px rgba(59, 130, 246, 0.1)" : "none"
|
|
2258
|
+
},
|
|
2259
|
+
onMouseEnter: (e) => {
|
|
2260
|
+
if (clickToSwitch && !isActive) {
|
|
2261
|
+
e.currentTarget.style.backgroundColor = "#f9fafb";
|
|
2262
|
+
e.currentTarget.style.borderColor = "#d1d5db";
|
|
2263
|
+
}
|
|
2264
|
+
},
|
|
2265
|
+
onMouseLeave: (e) => {
|
|
2266
|
+
if (clickToSwitch && !isActive) {
|
|
2267
|
+
e.currentTarget.style.backgroundColor = "#fff";
|
|
2268
|
+
e.currentTarget.style.borderColor = "#e5e7eb";
|
|
2269
|
+
}
|
|
2270
|
+
},
|
|
2271
|
+
children: [
|
|
2272
|
+
showAvatars && /* @__PURE__ */ jsx10("div", { style: avatarStyle, children: getInitials(account.name) }),
|
|
2273
|
+
/* @__PURE__ */ jsxs7("div", { style: { flex: 1, minWidth: 0 }, children: [
|
|
2274
|
+
/* @__PURE__ */ jsx10(
|
|
2275
|
+
"div",
|
|
2276
|
+
{
|
|
2277
|
+
style: {
|
|
2278
|
+
fontSize: "16px",
|
|
2279
|
+
fontWeight: "600",
|
|
2280
|
+
color: "#111827",
|
|
2281
|
+
marginBottom: showDetails ? "4px" : 0
|
|
2282
|
+
},
|
|
2283
|
+
children: account.name || account.username
|
|
2284
|
+
}
|
|
2285
|
+
),
|
|
2286
|
+
showDetails && /* @__PURE__ */ jsxs7(Fragment5, { children: [
|
|
2287
|
+
/* @__PURE__ */ jsx10(
|
|
2288
|
+
"div",
|
|
2289
|
+
{
|
|
2290
|
+
style: {
|
|
2291
|
+
fontSize: "14px",
|
|
2292
|
+
color: "#6b7280",
|
|
2293
|
+
overflow: "hidden",
|
|
2294
|
+
textOverflow: "ellipsis",
|
|
2295
|
+
whiteSpace: "nowrap"
|
|
2296
|
+
},
|
|
2297
|
+
children: account.username
|
|
2298
|
+
}
|
|
2299
|
+
),
|
|
2300
|
+
account.tenantId && /* @__PURE__ */ jsxs7(
|
|
2301
|
+
"div",
|
|
2302
|
+
{
|
|
2303
|
+
style: {
|
|
2304
|
+
fontSize: "12px",
|
|
2305
|
+
color: "#9ca3af",
|
|
2306
|
+
marginTop: "2px"
|
|
2307
|
+
},
|
|
2308
|
+
children: [
|
|
2309
|
+
"Tenant: ",
|
|
2310
|
+
account.tenantId.substring(0, 8),
|
|
2311
|
+
"..."
|
|
2312
|
+
]
|
|
2313
|
+
}
|
|
2314
|
+
)
|
|
2315
|
+
] })
|
|
2316
|
+
] }),
|
|
2317
|
+
showActiveIndicator && isActive && /* @__PURE__ */ jsxs7(
|
|
2318
|
+
"div",
|
|
2319
|
+
{
|
|
2320
|
+
style: {
|
|
2321
|
+
display: "flex",
|
|
2322
|
+
alignItems: "center",
|
|
2323
|
+
gap: "6px",
|
|
2324
|
+
padding: "4px 12px",
|
|
2325
|
+
backgroundColor: "#3b82f6",
|
|
2326
|
+
color: "#fff",
|
|
2327
|
+
borderRadius: "12px",
|
|
2328
|
+
fontSize: "12px",
|
|
2329
|
+
fontWeight: "600",
|
|
2330
|
+
flexShrink: 0
|
|
2331
|
+
},
|
|
2332
|
+
children: [
|
|
2333
|
+
/* @__PURE__ */ jsx10("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx10(
|
|
2334
|
+
"path",
|
|
2335
|
+
{
|
|
2336
|
+
d: "M10 3L4.5 8.5L2 6",
|
|
2337
|
+
stroke: "currentColor",
|
|
2338
|
+
strokeWidth: "2",
|
|
2339
|
+
strokeLinecap: "round",
|
|
2340
|
+
strokeLinejoin: "round"
|
|
2341
|
+
}
|
|
2342
|
+
) }),
|
|
2343
|
+
"Active"
|
|
2344
|
+
]
|
|
2345
|
+
}
|
|
2346
|
+
)
|
|
2347
|
+
]
|
|
2348
|
+
},
|
|
2349
|
+
account.homeAccountId
|
|
2350
|
+
);
|
|
2351
|
+
}) });
|
|
2352
|
+
}
|
|
2353
|
+
|
|
1689
2354
|
// src/hooks/useRoles.ts
|
|
1690
|
-
import { useState as
|
|
2355
|
+
import { useState as useState7, useEffect as useEffect8, useCallback as useCallback6 } from "react";
|
|
1691
2356
|
var rolesCache = /* @__PURE__ */ new Map();
|
|
1692
2357
|
var CACHE_DURATION2 = 5 * 60 * 1e3;
|
|
1693
2358
|
var MAX_CACHE_SIZE2 = 100;
|
|
@@ -1709,11 +2374,11 @@ function enforceCacheLimit2() {
|
|
|
1709
2374
|
function useRoles() {
|
|
1710
2375
|
const { isAuthenticated, account } = useMsalAuth();
|
|
1711
2376
|
const graph = useGraphApi();
|
|
1712
|
-
const [roles, setRoles] =
|
|
1713
|
-
const [groups, setGroups] =
|
|
1714
|
-
const [loading, setLoading] =
|
|
1715
|
-
const [error, setError] =
|
|
1716
|
-
const fetchRolesAndGroups =
|
|
2377
|
+
const [roles, setRoles] = useState7([]);
|
|
2378
|
+
const [groups, setGroups] = useState7([]);
|
|
2379
|
+
const [loading, setLoading] = useState7(false);
|
|
2380
|
+
const [error, setError] = useState7(null);
|
|
2381
|
+
const fetchRolesAndGroups = useCallback6(async () => {
|
|
1717
2382
|
if (!isAuthenticated || !account) {
|
|
1718
2383
|
setRoles([]);
|
|
1719
2384
|
setGroups([]);
|
|
@@ -1756,31 +2421,31 @@ function useRoles() {
|
|
|
1756
2421
|
setLoading(false);
|
|
1757
2422
|
}
|
|
1758
2423
|
}, [isAuthenticated, account, graph]);
|
|
1759
|
-
const hasRole =
|
|
2424
|
+
const hasRole = useCallback6(
|
|
1760
2425
|
(role) => {
|
|
1761
2426
|
return roles.includes(role);
|
|
1762
2427
|
},
|
|
1763
2428
|
[roles]
|
|
1764
2429
|
);
|
|
1765
|
-
const hasGroup =
|
|
2430
|
+
const hasGroup = useCallback6(
|
|
1766
2431
|
(groupId) => {
|
|
1767
2432
|
return groups.includes(groupId);
|
|
1768
2433
|
},
|
|
1769
2434
|
[groups]
|
|
1770
2435
|
);
|
|
1771
|
-
const hasAnyRole =
|
|
2436
|
+
const hasAnyRole = useCallback6(
|
|
1772
2437
|
(checkRoles) => {
|
|
1773
2438
|
return checkRoles.some((role) => roles.includes(role));
|
|
1774
2439
|
},
|
|
1775
2440
|
[roles]
|
|
1776
2441
|
);
|
|
1777
|
-
const hasAllRoles =
|
|
2442
|
+
const hasAllRoles = useCallback6(
|
|
1778
2443
|
(checkRoles) => {
|
|
1779
2444
|
return checkRoles.every((role) => roles.includes(role));
|
|
1780
2445
|
},
|
|
1781
2446
|
[roles]
|
|
1782
2447
|
);
|
|
1783
|
-
|
|
2448
|
+
useEffect8(() => {
|
|
1784
2449
|
fetchRolesAndGroups();
|
|
1785
2450
|
return () => {
|
|
1786
2451
|
if (account) {
|
|
@@ -1802,11 +2467,11 @@ function useRoles() {
|
|
|
1802
2467
|
}
|
|
1803
2468
|
|
|
1804
2469
|
// src/utils/withAuth.tsx
|
|
1805
|
-
import { jsx as
|
|
2470
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1806
2471
|
function withAuth(Component2, options = {}) {
|
|
1807
2472
|
const { displayName, ...guardProps } = options;
|
|
1808
2473
|
const WrappedComponent = (props) => {
|
|
1809
|
-
return /* @__PURE__ */
|
|
2474
|
+
return /* @__PURE__ */ jsx11(AuthGuard, { ...guardProps, children: /* @__PURE__ */ jsx11(Component2, { ...props }) });
|
|
1810
2475
|
};
|
|
1811
2476
|
WrappedComponent.displayName = displayName || `withAuth(${Component2.displayName || Component2.name || "Component"})`;
|
|
1812
2477
|
return WrappedComponent;
|
|
@@ -2078,9 +2743,9 @@ function createScopedLogger(scope, config) {
|
|
|
2078
2743
|
}
|
|
2079
2744
|
|
|
2080
2745
|
// src/protection/ProtectedPage.tsx
|
|
2081
|
-
import { useEffect as
|
|
2746
|
+
import { useEffect as useEffect9, useState as useState8 } from "react";
|
|
2082
2747
|
import { useRouter } from "next/navigation";
|
|
2083
|
-
import { Fragment as
|
|
2748
|
+
import { Fragment as Fragment6, jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2084
2749
|
function ProtectedPage({
|
|
2085
2750
|
children,
|
|
2086
2751
|
config,
|
|
@@ -2091,9 +2756,9 @@ function ProtectedPage({
|
|
|
2091
2756
|
}) {
|
|
2092
2757
|
const router = useRouter();
|
|
2093
2758
|
const { isAuthenticated, account, inProgress } = useMsalAuth();
|
|
2094
|
-
const [isValidating, setIsValidating] =
|
|
2095
|
-
const [isAuthorized, setIsAuthorized] =
|
|
2096
|
-
|
|
2759
|
+
const [isValidating, setIsValidating] = useState8(true);
|
|
2760
|
+
const [isAuthorized, setIsAuthorized] = useState8(false);
|
|
2761
|
+
useEffect9(() => {
|
|
2097
2762
|
async function checkAuth() {
|
|
2098
2763
|
if (debug) {
|
|
2099
2764
|
console.log("[ProtectedPage] Checking auth...", {
|
|
@@ -2162,33 +2827,33 @@ function ProtectedPage({
|
|
|
2162
2827
|
}, [isAuthenticated, account, inProgress, config, router, defaultRedirectTo, debug]);
|
|
2163
2828
|
if (isValidating || inProgress) {
|
|
2164
2829
|
if (config.loading) {
|
|
2165
|
-
return /* @__PURE__ */
|
|
2830
|
+
return /* @__PURE__ */ jsx12(Fragment6, { children: config.loading });
|
|
2166
2831
|
}
|
|
2167
2832
|
if (defaultLoading) {
|
|
2168
|
-
return /* @__PURE__ */
|
|
2833
|
+
return /* @__PURE__ */ jsx12(Fragment6, { children: defaultLoading });
|
|
2169
2834
|
}
|
|
2170
|
-
return /* @__PURE__ */
|
|
2835
|
+
return /* @__PURE__ */ jsx12("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsx12("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600" }) });
|
|
2171
2836
|
}
|
|
2172
2837
|
if (!isAuthorized) {
|
|
2173
2838
|
if (config.unauthorized) {
|
|
2174
|
-
return /* @__PURE__ */
|
|
2839
|
+
return /* @__PURE__ */ jsx12(Fragment6, { children: config.unauthorized });
|
|
2175
2840
|
}
|
|
2176
2841
|
if (defaultUnauthorized) {
|
|
2177
|
-
return /* @__PURE__ */
|
|
2842
|
+
return /* @__PURE__ */ jsx12(Fragment6, { children: defaultUnauthorized });
|
|
2178
2843
|
}
|
|
2179
|
-
return /* @__PURE__ */
|
|
2180
|
-
/* @__PURE__ */
|
|
2181
|
-
/* @__PURE__ */
|
|
2844
|
+
return /* @__PURE__ */ jsx12("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs8("div", { className: "text-center", children: [
|
|
2845
|
+
/* @__PURE__ */ jsx12("h1", { className: "text-2xl font-bold text-gray-900 mb-2", children: "Access Denied" }),
|
|
2846
|
+
/* @__PURE__ */ jsx12("p", { className: "text-gray-600", children: "You don't have permission to access this page." })
|
|
2182
2847
|
] }) });
|
|
2183
2848
|
}
|
|
2184
|
-
return /* @__PURE__ */
|
|
2849
|
+
return /* @__PURE__ */ jsx12(Fragment6, { children });
|
|
2185
2850
|
}
|
|
2186
2851
|
|
|
2187
2852
|
// src/protection/withPageAuth.tsx
|
|
2188
|
-
import { jsx as
|
|
2853
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
2189
2854
|
function withPageAuth(Component2, authConfig, globalConfig) {
|
|
2190
2855
|
const WrappedComponent = (props) => {
|
|
2191
|
-
return /* @__PURE__ */
|
|
2856
|
+
return /* @__PURE__ */ jsx13(
|
|
2192
2857
|
ProtectedPage,
|
|
2193
2858
|
{
|
|
2194
2859
|
config: authConfig,
|
|
@@ -2196,7 +2861,7 @@ function withPageAuth(Component2, authConfig, globalConfig) {
|
|
|
2196
2861
|
defaultLoading: globalConfig?.defaultLoading,
|
|
2197
2862
|
defaultUnauthorized: globalConfig?.defaultUnauthorized,
|
|
2198
2863
|
debug: globalConfig?.debug,
|
|
2199
|
-
children: /* @__PURE__ */
|
|
2864
|
+
children: /* @__PURE__ */ jsx13(Component2, { ...props })
|
|
2200
2865
|
}
|
|
2201
2866
|
);
|
|
2202
2867
|
};
|
|
@@ -2278,8 +2943,10 @@ function createAuthMiddleware(config = {}) {
|
|
|
2278
2943
|
}
|
|
2279
2944
|
|
|
2280
2945
|
// src/client.ts
|
|
2281
|
-
import { useMsal as
|
|
2946
|
+
import { useMsal as useMsal3, useIsAuthenticated, useAccount as useAccount2 } from "@azure/msal-react";
|
|
2282
2947
|
export {
|
|
2948
|
+
AccountList,
|
|
2949
|
+
AccountSwitcher,
|
|
2283
2950
|
AuthGuard,
|
|
2284
2951
|
AuthStatus,
|
|
2285
2952
|
ErrorBoundary,
|
|
@@ -2307,8 +2974,9 @@ export {
|
|
|
2307
2974
|
useAccount2 as useAccount,
|
|
2308
2975
|
useGraphApi,
|
|
2309
2976
|
useIsAuthenticated,
|
|
2310
|
-
|
|
2977
|
+
useMsal3 as useMsal,
|
|
2311
2978
|
useMsalAuth,
|
|
2979
|
+
useMultiAccount,
|
|
2312
2980
|
useRoles,
|
|
2313
2981
|
useTokenRefresh,
|
|
2314
2982
|
useUserProfile,
|