nextauthz 1.1.6 → 1.1.7
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/dist/index.d.mts +37 -4
- package/dist/index.d.ts +37 -4
- package/dist/index.js +121 -26
- package/dist/index.mjs +119 -26
- package/package.json +1 -1
- package/src/AuthProvider.tsx +109 -135
- package/src/RoleGuard.tsx +40 -40
- package/src/index.ts +8 -8
- package/src/myAuth.ts +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -1,18 +1,51 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import React__default, { ReactNode } from 'react';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
type AuthContextType<UserType> = {
|
|
6
|
+
user: UserType | null;
|
|
7
|
+
login: (tokens: Record<string, string>, user: UserType) => void;
|
|
8
|
+
logout: () => void;
|
|
9
|
+
setUser: (user: UserType) => void;
|
|
10
|
+
loading: boolean;
|
|
11
|
+
error: Error | null;
|
|
12
|
+
};
|
|
13
|
+
type AuthContextOptions = {
|
|
14
|
+
storage?: 'localStorage' | 'sessionStorage' | 'cookie';
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Factory to create AuthProvider and typed useAuth hook
|
|
18
|
+
*/
|
|
19
|
+
declare function createAuthContext<UserType>(options?: AuthContextOptions): {
|
|
20
|
+
AuthProvider: ({ children }: {
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
23
|
+
useAuth: () => AuthContextType<UserType>;
|
|
24
|
+
};
|
|
5
25
|
|
|
6
26
|
type AuthGuardProps = {
|
|
7
|
-
children:
|
|
27
|
+
children: React__default.ReactNode;
|
|
8
28
|
redirectTo?: string;
|
|
9
29
|
tokenKey?: string;
|
|
10
30
|
refreshToken?: () => Promise<string | null>;
|
|
11
31
|
};
|
|
12
32
|
declare const AuthGuard: ({ children, redirectTo, tokenKey, refreshToken, }: AuthGuardProps) => react_jsx_runtime.JSX.Element | null;
|
|
13
33
|
|
|
34
|
+
type RoleGuardProps = {
|
|
35
|
+
children: React__default.ReactNode;
|
|
36
|
+
allowedRoles: string[];
|
|
37
|
+
redirectTo?: string;
|
|
38
|
+
};
|
|
39
|
+
declare const RoleGuard: React__default.FC<RoleGuardProps>;
|
|
40
|
+
|
|
14
41
|
type User = {
|
|
15
42
|
[key: string]: any;
|
|
16
43
|
};
|
|
44
|
+
declare function createAppAuth(storage?: 'localStorage' | 'sessionStorage' | 'cookie'): {
|
|
45
|
+
AuthProvider: ({ children }: {
|
|
46
|
+
children: React.ReactNode;
|
|
47
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
48
|
+
useAuth: () => AuthContextType<User>;
|
|
49
|
+
};
|
|
17
50
|
|
|
18
|
-
export { AuthGuard,
|
|
51
|
+
export { AuthGuard, RoleGuard, type User, createAppAuth, createAuthContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,51 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import React__default, { ReactNode } from 'react';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
type AuthContextType<UserType> = {
|
|
6
|
+
user: UserType | null;
|
|
7
|
+
login: (tokens: Record<string, string>, user: UserType) => void;
|
|
8
|
+
logout: () => void;
|
|
9
|
+
setUser: (user: UserType) => void;
|
|
10
|
+
loading: boolean;
|
|
11
|
+
error: Error | null;
|
|
12
|
+
};
|
|
13
|
+
type AuthContextOptions = {
|
|
14
|
+
storage?: 'localStorage' | 'sessionStorage' | 'cookie';
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Factory to create AuthProvider and typed useAuth hook
|
|
18
|
+
*/
|
|
19
|
+
declare function createAuthContext<UserType>(options?: AuthContextOptions): {
|
|
20
|
+
AuthProvider: ({ children }: {
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
23
|
+
useAuth: () => AuthContextType<UserType>;
|
|
24
|
+
};
|
|
5
25
|
|
|
6
26
|
type AuthGuardProps = {
|
|
7
|
-
children:
|
|
27
|
+
children: React__default.ReactNode;
|
|
8
28
|
redirectTo?: string;
|
|
9
29
|
tokenKey?: string;
|
|
10
30
|
refreshToken?: () => Promise<string | null>;
|
|
11
31
|
};
|
|
12
32
|
declare const AuthGuard: ({ children, redirectTo, tokenKey, refreshToken, }: AuthGuardProps) => react_jsx_runtime.JSX.Element | null;
|
|
13
33
|
|
|
34
|
+
type RoleGuardProps = {
|
|
35
|
+
children: React__default.ReactNode;
|
|
36
|
+
allowedRoles: string[];
|
|
37
|
+
redirectTo?: string;
|
|
38
|
+
};
|
|
39
|
+
declare const RoleGuard: React__default.FC<RoleGuardProps>;
|
|
40
|
+
|
|
14
41
|
type User = {
|
|
15
42
|
[key: string]: any;
|
|
16
43
|
};
|
|
44
|
+
declare function createAppAuth(storage?: 'localStorage' | 'sessionStorage' | 'cookie'): {
|
|
45
|
+
AuthProvider: ({ children }: {
|
|
46
|
+
children: React.ReactNode;
|
|
47
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
48
|
+
useAuth: () => AuthContextType<User>;
|
|
49
|
+
};
|
|
17
50
|
|
|
18
|
-
export { AuthGuard,
|
|
51
|
+
export { AuthGuard, RoleGuard, type User, createAppAuth, createAuthContext };
|
package/dist/index.js
CHANGED
|
@@ -1699,18 +1699,18 @@ var require_react_jsx_runtime_development = __commonJS({
|
|
|
1699
1699
|
function isValidElement(object) {
|
|
1700
1700
|
return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE;
|
|
1701
1701
|
}
|
|
1702
|
-
var
|
|
1702
|
+
var React4 = require_react(), REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = /* @__PURE__ */ Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = /* @__PURE__ */ Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = /* @__PURE__ */ Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = /* @__PURE__ */ Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = /* @__PURE__ */ Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = /* @__PURE__ */ Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = /* @__PURE__ */ Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = /* @__PURE__ */ Symbol.for("react.memo"), REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = /* @__PURE__ */ Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = /* @__PURE__ */ Symbol.for("react.client.reference"), ReactSharedInternals = React4.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
|
|
1703
1703
|
return null;
|
|
1704
1704
|
};
|
|
1705
|
-
|
|
1705
|
+
React4 = {
|
|
1706
1706
|
react_stack_bottom_frame: function(callStackForError) {
|
|
1707
1707
|
return callStackForError();
|
|
1708
1708
|
}
|
|
1709
1709
|
};
|
|
1710
1710
|
var specialPropKeyWarningShown;
|
|
1711
1711
|
var didWarnAboutElementRef = {};
|
|
1712
|
-
var unknownOwnerDebugStack =
|
|
1713
|
-
|
|
1712
|
+
var unknownOwnerDebugStack = React4.react_stack_bottom_frame.bind(
|
|
1713
|
+
React4,
|
|
1714
1714
|
UnknownOwner
|
|
1715
1715
|
)();
|
|
1716
1716
|
var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
|
|
@@ -1758,31 +1758,14 @@ var require_jsx_runtime = __commonJS({
|
|
|
1758
1758
|
var index_exports = {};
|
|
1759
1759
|
__export(index_exports, {
|
|
1760
1760
|
AuthGuard: () => AuthGuard_default,
|
|
1761
|
-
|
|
1761
|
+
RoleGuard: () => RoleGuard_default,
|
|
1762
|
+
createAppAuth: () => createAppAuth,
|
|
1763
|
+
createAuthContext: () => createAuthContext
|
|
1762
1764
|
});
|
|
1763
1765
|
module.exports = __toCommonJS(index_exports);
|
|
1764
1766
|
|
|
1765
1767
|
// src/AuthProvider.tsx
|
|
1766
1768
|
var import_react = __toESM(require_react());
|
|
1767
|
-
var import_jsx_runtime = __toESM(require_jsx_runtime());
|
|
1768
|
-
var ThemeContext = (0, import_react.createContext)({
|
|
1769
|
-
theme: "light",
|
|
1770
|
-
// default value
|
|
1771
|
-
toggleTheme: () => {
|
|
1772
|
-
}
|
|
1773
|
-
// default empty function
|
|
1774
|
-
});
|
|
1775
|
-
var ThemeProvider = ({ children }) => {
|
|
1776
|
-
const [theme, setTheme] = (0, import_react.useState)("light");
|
|
1777
|
-
const toggleTheme = () => {
|
|
1778
|
-
setTheme((prev) => prev === "light" ? "dark" : "light");
|
|
1779
|
-
};
|
|
1780
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value: { theme, toggleTheme }, children });
|
|
1781
|
-
};
|
|
1782
|
-
|
|
1783
|
-
// src/AuthGuard.tsx
|
|
1784
|
-
var import_react2 = __toESM(require_react());
|
|
1785
|
-
var import_navigation = require("next/navigation");
|
|
1786
1769
|
var import_react_token_manager = require("react-token-manager");
|
|
1787
1770
|
|
|
1788
1771
|
// store/useGuardStore.ts
|
|
@@ -1804,7 +1787,81 @@ var useAuthStore = (0, import_zustand.create)((set) => ({
|
|
|
1804
1787
|
})
|
|
1805
1788
|
}));
|
|
1806
1789
|
|
|
1790
|
+
// src/AuthProvider.tsx
|
|
1791
|
+
var import_jsx_runtime = __toESM(require_jsx_runtime());
|
|
1792
|
+
function createAuthContext(options) {
|
|
1793
|
+
const AuthContext = (0, import_react.createContext)(null);
|
|
1794
|
+
const AuthProvider = ({ children }) => {
|
|
1795
|
+
const storageType = options?.storage || "cookie";
|
|
1796
|
+
(0, import_react.useEffect)(() => {
|
|
1797
|
+
(0, import_react_token_manager.configureTokenManager)({ storage: storageType });
|
|
1798
|
+
}, [storageType]);
|
|
1799
|
+
const manager = (0, import_react_token_manager.useTokenManager)();
|
|
1800
|
+
const [loading, setLoading] = (0, import_react.useState)(true);
|
|
1801
|
+
const rawUser = useAuthStore((state) => state.user);
|
|
1802
|
+
const error = useAuthStore((state) => state.error);
|
|
1803
|
+
const user = rawUser;
|
|
1804
|
+
(0, import_react.useEffect)(() => {
|
|
1805
|
+
const savedUser = manager.getSingleToken("user");
|
|
1806
|
+
if (savedUser) {
|
|
1807
|
+
try {
|
|
1808
|
+
const parsedUser = JSON.parse(savedUser);
|
|
1809
|
+
useAuthStore.getState().setUser(parsedUser);
|
|
1810
|
+
useAuthStore.getState().setError(null);
|
|
1811
|
+
} catch {
|
|
1812
|
+
useAuthStore.getState().resetAuth();
|
|
1813
|
+
useAuthStore.getState().setError(
|
|
1814
|
+
new Error("Failed to parse saved user")
|
|
1815
|
+
);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
setLoading(false);
|
|
1819
|
+
}, [manager]);
|
|
1820
|
+
const setUser = (userData) => {
|
|
1821
|
+
useAuthStore.getState().setUser(userData);
|
|
1822
|
+
useAuthStore.getState().setError(null);
|
|
1823
|
+
manager.setTokens({ user: JSON.stringify(userData) });
|
|
1824
|
+
};
|
|
1825
|
+
const login = (tokens, userData) => {
|
|
1826
|
+
try {
|
|
1827
|
+
manager.setTokens(tokens);
|
|
1828
|
+
setUser(userData);
|
|
1829
|
+
} catch (err) {
|
|
1830
|
+
useAuthStore.getState().setError(
|
|
1831
|
+
err instanceof Error ? err : new Error(String(err))
|
|
1832
|
+
);
|
|
1833
|
+
}
|
|
1834
|
+
};
|
|
1835
|
+
const logout = () => {
|
|
1836
|
+
try {
|
|
1837
|
+
manager.clearTokens();
|
|
1838
|
+
useAuthStore.getState().resetAuth();
|
|
1839
|
+
} catch (err) {
|
|
1840
|
+
useAuthStore.getState().setError(
|
|
1841
|
+
err instanceof Error ? err : new Error(String(err))
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
};
|
|
1845
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1846
|
+
AuthContext.Provider,
|
|
1847
|
+
{
|
|
1848
|
+
value: { user, login, logout, setUser, loading, error },
|
|
1849
|
+
children
|
|
1850
|
+
}
|
|
1851
|
+
);
|
|
1852
|
+
};
|
|
1853
|
+
const useAuth = () => {
|
|
1854
|
+
const ctx = (0, import_react.useContext)(AuthContext);
|
|
1855
|
+
if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
|
|
1856
|
+
return ctx;
|
|
1857
|
+
};
|
|
1858
|
+
return { AuthProvider, useAuth };
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1807
1861
|
// src/AuthGuard.tsx
|
|
1862
|
+
var import_react2 = __toESM(require_react());
|
|
1863
|
+
var import_navigation = require("next/navigation");
|
|
1864
|
+
var import_react_token_manager2 = require("react-token-manager");
|
|
1808
1865
|
var import_jsx_runtime2 = __toESM(require_jsx_runtime());
|
|
1809
1866
|
var AuthGuard = ({
|
|
1810
1867
|
children,
|
|
@@ -1812,7 +1869,7 @@ var AuthGuard = ({
|
|
|
1812
1869
|
tokenKey = "access_token",
|
|
1813
1870
|
refreshToken
|
|
1814
1871
|
}) => {
|
|
1815
|
-
const manager = (0,
|
|
1872
|
+
const manager = (0, import_react_token_manager2.useTokenManager)();
|
|
1816
1873
|
const router = (0, import_navigation.useRouter)();
|
|
1817
1874
|
const isAuthChecked = useAuthStore((state) => state.isAuthChecked);
|
|
1818
1875
|
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
|
@@ -1854,10 +1911,48 @@ var AuthGuard = ({
|
|
|
1854
1911
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
|
|
1855
1912
|
};
|
|
1856
1913
|
var AuthGuard_default = AuthGuard;
|
|
1914
|
+
|
|
1915
|
+
// src/RoleGuard.tsx
|
|
1916
|
+
var import_react3 = __toESM(require_react());
|
|
1917
|
+
var import_navigation2 = require("next/navigation");
|
|
1918
|
+
|
|
1919
|
+
// src/myAuth.ts
|
|
1920
|
+
var auth = createAppAuth();
|
|
1921
|
+
|
|
1922
|
+
// src/RoleGuard.tsx
|
|
1923
|
+
var import_jsx_runtime3 = __toESM(require_jsx_runtime());
|
|
1924
|
+
var RoleGuard = ({
|
|
1925
|
+
children,
|
|
1926
|
+
allowedRoles,
|
|
1927
|
+
redirectTo = "/unauthorized"
|
|
1928
|
+
}) => {
|
|
1929
|
+
const { useAuth } = auth;
|
|
1930
|
+
const { user, loading } = useAuth();
|
|
1931
|
+
const router = (0, import_navigation2.useRouter)();
|
|
1932
|
+
const [isChecking, setIsChecking] = (0, import_react3.useState)(true);
|
|
1933
|
+
(0, import_react3.useEffect)(() => {
|
|
1934
|
+
if (!user) return;
|
|
1935
|
+
const hasAccess = allowedRoles.includes(user?.role);
|
|
1936
|
+
if (!hasAccess) {
|
|
1937
|
+
router.replace(redirectTo);
|
|
1938
|
+
}
|
|
1939
|
+
setIsChecking(false);
|
|
1940
|
+
}, [user, allowedRoles, redirectTo, router]);
|
|
1941
|
+
if (loading || !user || isChecking) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: "Loading..." });
|
|
1942
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
|
|
1943
|
+
};
|
|
1944
|
+
var RoleGuard_default = RoleGuard;
|
|
1945
|
+
|
|
1946
|
+
// src/index.ts
|
|
1947
|
+
function createAppAuth(storage = "cookie") {
|
|
1948
|
+
return createAuthContext({ storage });
|
|
1949
|
+
}
|
|
1857
1950
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1858
1951
|
0 && (module.exports = {
|
|
1859
1952
|
AuthGuard,
|
|
1860
|
-
|
|
1953
|
+
RoleGuard,
|
|
1954
|
+
createAppAuth,
|
|
1955
|
+
createAuthContext
|
|
1861
1956
|
});
|
|
1862
1957
|
/*! Bundled license information:
|
|
1863
1958
|
|
package/dist/index.mjs
CHANGED
|
@@ -1693,18 +1693,18 @@ var require_react_jsx_runtime_development = __commonJS({
|
|
|
1693
1693
|
function isValidElement(object) {
|
|
1694
1694
|
return "object" === typeof object && null !== object && object.$$typeof === REACT_ELEMENT_TYPE;
|
|
1695
1695
|
}
|
|
1696
|
-
var
|
|
1696
|
+
var React4 = require_react(), REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = /* @__PURE__ */ Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = /* @__PURE__ */ Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = /* @__PURE__ */ Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = /* @__PURE__ */ Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = /* @__PURE__ */ Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = /* @__PURE__ */ Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = /* @__PURE__ */ Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = /* @__PURE__ */ Symbol.for("react.memo"), REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for("react.lazy"), REACT_ACTIVITY_TYPE = /* @__PURE__ */ Symbol.for("react.activity"), REACT_CLIENT_REFERENCE = /* @__PURE__ */ Symbol.for("react.client.reference"), ReactSharedInternals = React4.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, hasOwnProperty = Object.prototype.hasOwnProperty, isArrayImpl = Array.isArray, createTask = console.createTask ? console.createTask : function() {
|
|
1697
1697
|
return null;
|
|
1698
1698
|
};
|
|
1699
|
-
|
|
1699
|
+
React4 = {
|
|
1700
1700
|
react_stack_bottom_frame: function(callStackForError) {
|
|
1701
1701
|
return callStackForError();
|
|
1702
1702
|
}
|
|
1703
1703
|
};
|
|
1704
1704
|
var specialPropKeyWarningShown;
|
|
1705
1705
|
var didWarnAboutElementRef = {};
|
|
1706
|
-
var unknownOwnerDebugStack =
|
|
1707
|
-
|
|
1706
|
+
var unknownOwnerDebugStack = React4.react_stack_bottom_frame.bind(
|
|
1707
|
+
React4,
|
|
1708
1708
|
UnknownOwner
|
|
1709
1709
|
)();
|
|
1710
1710
|
var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));
|
|
@@ -1750,26 +1750,7 @@ var require_jsx_runtime = __commonJS({
|
|
|
1750
1750
|
|
|
1751
1751
|
// src/AuthProvider.tsx
|
|
1752
1752
|
var import_react = __toESM(require_react());
|
|
1753
|
-
|
|
1754
|
-
var ThemeContext = (0, import_react.createContext)({
|
|
1755
|
-
theme: "light",
|
|
1756
|
-
// default value
|
|
1757
|
-
toggleTheme: () => {
|
|
1758
|
-
}
|
|
1759
|
-
// default empty function
|
|
1760
|
-
});
|
|
1761
|
-
var ThemeProvider = ({ children }) => {
|
|
1762
|
-
const [theme, setTheme] = (0, import_react.useState)("light");
|
|
1763
|
-
const toggleTheme = () => {
|
|
1764
|
-
setTheme((prev) => prev === "light" ? "dark" : "light");
|
|
1765
|
-
};
|
|
1766
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value: { theme, toggleTheme }, children });
|
|
1767
|
-
};
|
|
1768
|
-
|
|
1769
|
-
// src/AuthGuard.tsx
|
|
1770
|
-
var import_react2 = __toESM(require_react());
|
|
1771
|
-
import { useRouter } from "next/navigation";
|
|
1772
|
-
import { useTokenManager } from "react-token-manager";
|
|
1753
|
+
import { configureTokenManager, useTokenManager } from "react-token-manager";
|
|
1773
1754
|
|
|
1774
1755
|
// store/useGuardStore.ts
|
|
1775
1756
|
import { create } from "zustand";
|
|
@@ -1790,7 +1771,81 @@ var useAuthStore = create((set) => ({
|
|
|
1790
1771
|
})
|
|
1791
1772
|
}));
|
|
1792
1773
|
|
|
1774
|
+
// src/AuthProvider.tsx
|
|
1775
|
+
var import_jsx_runtime = __toESM(require_jsx_runtime());
|
|
1776
|
+
function createAuthContext(options) {
|
|
1777
|
+
const AuthContext = (0, import_react.createContext)(null);
|
|
1778
|
+
const AuthProvider = ({ children }) => {
|
|
1779
|
+
const storageType = options?.storage || "cookie";
|
|
1780
|
+
(0, import_react.useEffect)(() => {
|
|
1781
|
+
configureTokenManager({ storage: storageType });
|
|
1782
|
+
}, [storageType]);
|
|
1783
|
+
const manager = useTokenManager();
|
|
1784
|
+
const [loading, setLoading] = (0, import_react.useState)(true);
|
|
1785
|
+
const rawUser = useAuthStore((state) => state.user);
|
|
1786
|
+
const error = useAuthStore((state) => state.error);
|
|
1787
|
+
const user = rawUser;
|
|
1788
|
+
(0, import_react.useEffect)(() => {
|
|
1789
|
+
const savedUser = manager.getSingleToken("user");
|
|
1790
|
+
if (savedUser) {
|
|
1791
|
+
try {
|
|
1792
|
+
const parsedUser = JSON.parse(savedUser);
|
|
1793
|
+
useAuthStore.getState().setUser(parsedUser);
|
|
1794
|
+
useAuthStore.getState().setError(null);
|
|
1795
|
+
} catch {
|
|
1796
|
+
useAuthStore.getState().resetAuth();
|
|
1797
|
+
useAuthStore.getState().setError(
|
|
1798
|
+
new Error("Failed to parse saved user")
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
setLoading(false);
|
|
1803
|
+
}, [manager]);
|
|
1804
|
+
const setUser = (userData) => {
|
|
1805
|
+
useAuthStore.getState().setUser(userData);
|
|
1806
|
+
useAuthStore.getState().setError(null);
|
|
1807
|
+
manager.setTokens({ user: JSON.stringify(userData) });
|
|
1808
|
+
};
|
|
1809
|
+
const login = (tokens, userData) => {
|
|
1810
|
+
try {
|
|
1811
|
+
manager.setTokens(tokens);
|
|
1812
|
+
setUser(userData);
|
|
1813
|
+
} catch (err) {
|
|
1814
|
+
useAuthStore.getState().setError(
|
|
1815
|
+
err instanceof Error ? err : new Error(String(err))
|
|
1816
|
+
);
|
|
1817
|
+
}
|
|
1818
|
+
};
|
|
1819
|
+
const logout = () => {
|
|
1820
|
+
try {
|
|
1821
|
+
manager.clearTokens();
|
|
1822
|
+
useAuthStore.getState().resetAuth();
|
|
1823
|
+
} catch (err) {
|
|
1824
|
+
useAuthStore.getState().setError(
|
|
1825
|
+
err instanceof Error ? err : new Error(String(err))
|
|
1826
|
+
);
|
|
1827
|
+
}
|
|
1828
|
+
};
|
|
1829
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1830
|
+
AuthContext.Provider,
|
|
1831
|
+
{
|
|
1832
|
+
value: { user, login, logout, setUser, loading, error },
|
|
1833
|
+
children
|
|
1834
|
+
}
|
|
1835
|
+
);
|
|
1836
|
+
};
|
|
1837
|
+
const useAuth = () => {
|
|
1838
|
+
const ctx = (0, import_react.useContext)(AuthContext);
|
|
1839
|
+
if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
|
|
1840
|
+
return ctx;
|
|
1841
|
+
};
|
|
1842
|
+
return { AuthProvider, useAuth };
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1793
1845
|
// src/AuthGuard.tsx
|
|
1846
|
+
var import_react2 = __toESM(require_react());
|
|
1847
|
+
import { useRouter } from "next/navigation";
|
|
1848
|
+
import { useTokenManager as useTokenManager2 } from "react-token-manager";
|
|
1794
1849
|
var import_jsx_runtime2 = __toESM(require_jsx_runtime());
|
|
1795
1850
|
var AuthGuard = ({
|
|
1796
1851
|
children,
|
|
@@ -1798,7 +1853,7 @@ var AuthGuard = ({
|
|
|
1798
1853
|
tokenKey = "access_token",
|
|
1799
1854
|
refreshToken
|
|
1800
1855
|
}) => {
|
|
1801
|
-
const manager =
|
|
1856
|
+
const manager = useTokenManager2();
|
|
1802
1857
|
const router = useRouter();
|
|
1803
1858
|
const isAuthChecked = useAuthStore((state) => state.isAuthChecked);
|
|
1804
1859
|
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
|
@@ -1840,9 +1895,47 @@ var AuthGuard = ({
|
|
|
1840
1895
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
|
|
1841
1896
|
};
|
|
1842
1897
|
var AuthGuard_default = AuthGuard;
|
|
1898
|
+
|
|
1899
|
+
// src/RoleGuard.tsx
|
|
1900
|
+
var import_react3 = __toESM(require_react());
|
|
1901
|
+
import { useRouter as useRouter2 } from "next/navigation";
|
|
1902
|
+
|
|
1903
|
+
// src/myAuth.ts
|
|
1904
|
+
var auth = createAppAuth();
|
|
1905
|
+
|
|
1906
|
+
// src/RoleGuard.tsx
|
|
1907
|
+
var import_jsx_runtime3 = __toESM(require_jsx_runtime());
|
|
1908
|
+
var RoleGuard = ({
|
|
1909
|
+
children,
|
|
1910
|
+
allowedRoles,
|
|
1911
|
+
redirectTo = "/unauthorized"
|
|
1912
|
+
}) => {
|
|
1913
|
+
const { useAuth } = auth;
|
|
1914
|
+
const { user, loading } = useAuth();
|
|
1915
|
+
const router = useRouter2();
|
|
1916
|
+
const [isChecking, setIsChecking] = (0, import_react3.useState)(true);
|
|
1917
|
+
(0, import_react3.useEffect)(() => {
|
|
1918
|
+
if (!user) return;
|
|
1919
|
+
const hasAccess = allowedRoles.includes(user?.role);
|
|
1920
|
+
if (!hasAccess) {
|
|
1921
|
+
router.replace(redirectTo);
|
|
1922
|
+
}
|
|
1923
|
+
setIsChecking(false);
|
|
1924
|
+
}, [user, allowedRoles, redirectTo, router]);
|
|
1925
|
+
if (loading || !user || isChecking) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: "Loading..." });
|
|
1926
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
|
|
1927
|
+
};
|
|
1928
|
+
var RoleGuard_default = RoleGuard;
|
|
1929
|
+
|
|
1930
|
+
// src/index.ts
|
|
1931
|
+
function createAppAuth(storage = "cookie") {
|
|
1932
|
+
return createAuthContext({ storage });
|
|
1933
|
+
}
|
|
1843
1934
|
export {
|
|
1844
1935
|
AuthGuard_default as AuthGuard,
|
|
1845
|
-
|
|
1936
|
+
RoleGuard_default as RoleGuard,
|
|
1937
|
+
createAppAuth,
|
|
1938
|
+
createAuthContext
|
|
1846
1939
|
};
|
|
1847
1940
|
/*! Bundled license information:
|
|
1848
1941
|
|
package/package.json
CHANGED
package/src/AuthProvider.tsx
CHANGED
|
@@ -1,137 +1,111 @@
|
|
|
1
|
-
// 'use client'
|
|
2
|
-
|
|
3
|
-
// import React, {
|
|
4
|
-
// createContext,
|
|
5
|
-
// useContext,
|
|
6
|
-
// ReactNode,
|
|
7
|
-
// useEffect,
|
|
8
|
-
// useState,
|
|
9
|
-
// } from 'react'
|
|
10
|
-
// import { configureTokenManager, useTokenManager } from 'react-token-manager'
|
|
11
|
-
// import { useAuthStore } from '../store/useGuardStore'
|
|
12
|
-
|
|
13
|
-
// export type AuthContextType<UserType> = {
|
|
14
|
-
// user: UserType | null
|
|
15
|
-
// login: (tokens: Record<string, string>, user: UserType) => void
|
|
16
|
-
// logout: () => void
|
|
17
|
-
// setUser: (user: UserType) => void
|
|
18
|
-
// loading: boolean
|
|
19
|
-
// error: Error | null
|
|
20
|
-
// }
|
|
21
|
-
|
|
22
|
-
// export type AuthContextOptions = {
|
|
23
|
-
// storage?: 'localStorage' | 'sessionStorage' | 'cookie'
|
|
24
|
-
// }
|
|
25
|
-
|
|
26
|
-
// /**
|
|
27
|
-
// * Factory to create AuthProvider and typed useAuth hook
|
|
28
|
-
// */
|
|
29
|
-
// export function createAuthContext<UserType>(options?: AuthContextOptions) {
|
|
30
|
-
// const AuthContext = createContext<AuthContextType<UserType> | null>(null)
|
|
31
|
-
|
|
32
|
-
// const AuthProvider = ({ children }: { children: ReactNode }) => {
|
|
33
|
-
// const storageType = options?.storage || 'cookie'
|
|
34
|
-
|
|
35
|
-
// // Configure token manager once on mount
|
|
36
|
-
// useEffect(() => {
|
|
37
|
-
// configureTokenManager({ storage: storageType })
|
|
38
|
-
// }, [storageType])
|
|
39
|
-
|
|
40
|
-
// // ✅ Hooks must be called inside component
|
|
41
|
-
// const manager = useTokenManager()
|
|
42
|
-
|
|
43
|
-
// const [loading, setLoading] = useState(true)
|
|
44
|
-
|
|
45
|
-
// const rawUser = useAuthStore((state) => state.user)
|
|
46
|
-
// const error = useAuthStore((state) => state.error)
|
|
47
|
-
// const user = rawUser as UserType | null
|
|
48
|
-
|
|
49
|
-
// // Restore saved user from token manager
|
|
50
|
-
// useEffect(() => {
|
|
51
|
-
// const savedUser = manager.getSingleToken('user')
|
|
52
|
-
// if (savedUser) {
|
|
53
|
-
// try {
|
|
54
|
-
// const parsedUser = JSON.parse(savedUser)
|
|
55
|
-
// useAuthStore.getState().setUser(parsedUser)
|
|
56
|
-
// useAuthStore.getState().setError(null)
|
|
57
|
-
// } catch {
|
|
58
|
-
// useAuthStore.getState().resetAuth()
|
|
59
|
-
// useAuthStore.getState().setError(
|
|
60
|
-
// new Error('Failed to parse saved user')
|
|
61
|
-
// )
|
|
62
|
-
// }
|
|
63
|
-
// }
|
|
64
|
-
// setLoading(false)
|
|
65
|
-
// }, [manager])
|
|
66
|
-
|
|
67
|
-
// const setUser = (userData: UserType) => {
|
|
68
|
-
// useAuthStore.getState().setUser(userData as any)
|
|
69
|
-
// useAuthStore.getState().setError(null)
|
|
70
|
-
// manager.setTokens({ user: JSON.stringify(userData) })
|
|
71
|
-
// }
|
|
72
|
-
|
|
73
|
-
// const login = (tokens: Record<string, string>, userData: UserType) => {
|
|
74
|
-
// try {
|
|
75
|
-
// manager.setTokens(tokens)
|
|
76
|
-
// setUser(userData)
|
|
77
|
-
// } catch (err) {
|
|
78
|
-
// useAuthStore.getState().setError(
|
|
79
|
-
// err instanceof Error ? err : new Error(String(err))
|
|
80
|
-
// )
|
|
81
|
-
// }
|
|
82
|
-
// }
|
|
83
|
-
|
|
84
|
-
// const logout = () => {
|
|
85
|
-
// try {
|
|
86
|
-
// manager.clearTokens()
|
|
87
|
-
// useAuthStore.getState().resetAuth()
|
|
88
|
-
// } catch (err) {
|
|
89
|
-
// useAuthStore.getState().setError(
|
|
90
|
-
// err instanceof Error ? err : new Error(String(err))
|
|
91
|
-
// )
|
|
92
|
-
// }
|
|
93
|
-
// }
|
|
94
|
-
|
|
95
|
-
// return (
|
|
96
|
-
// <AuthContext.Provider
|
|
97
|
-
// value={{ user, login, logout, setUser, loading, error }}
|
|
98
|
-
// >
|
|
99
|
-
// {children}
|
|
100
|
-
// </AuthContext.Provider>
|
|
101
|
-
// )
|
|
102
|
-
// }
|
|
103
|
-
|
|
104
|
-
// const useAuth = (): AuthContextType<UserType> => {
|
|
105
|
-
// const ctx = useContext(AuthContext)
|
|
106
|
-
// if (!ctx) throw new Error('useAuth must be used inside AuthProvider')
|
|
107
|
-
// return ctx
|
|
108
|
-
// }
|
|
109
|
-
|
|
110
|
-
// return { AuthProvider, useAuth }
|
|
111
|
-
// }
|
|
112
|
-
|
|
113
|
-
// src/context/ThemeContext.js
|
|
114
1
|
'use client'
|
|
115
|
-
import { createContext, useState } from 'react';
|
|
116
|
-
|
|
117
|
-
// 1️⃣ Create the context
|
|
118
|
-
export const ThemeContext = createContext({
|
|
119
|
-
theme: 'light', // default value
|
|
120
|
-
toggleTheme: () => {} // default empty function
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// 2️⃣ Create the provider component
|
|
124
|
-
export const ThemeProvider = ({ children }: any) => {
|
|
125
|
-
const [theme, setTheme] = useState('light');
|
|
126
|
-
|
|
127
|
-
const toggleTheme = () => {
|
|
128
|
-
setTheme(prev => (prev === 'light' ? 'dark' : 'light'));
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
return (
|
|
132
|
-
<ThemeContext.Provider value={{ theme, toggleTheme }}>
|
|
133
|
-
{children}
|
|
134
|
-
</ThemeContext.Provider>
|
|
135
|
-
);
|
|
136
|
-
};
|
|
137
2
|
|
|
3
|
+
import React, {
|
|
4
|
+
createContext,
|
|
5
|
+
useContext,
|
|
6
|
+
ReactNode,
|
|
7
|
+
useEffect,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react'
|
|
10
|
+
import { configureTokenManager, useTokenManager } from 'react-token-manager'
|
|
11
|
+
import { useAuthStore } from '../store/useGuardStore'
|
|
12
|
+
|
|
13
|
+
export type AuthContextType<UserType> = {
|
|
14
|
+
user: UserType | null
|
|
15
|
+
login: (tokens: Record<string, string>, user: UserType) => void
|
|
16
|
+
logout: () => void
|
|
17
|
+
setUser: (user: UserType) => void
|
|
18
|
+
loading: boolean
|
|
19
|
+
error: Error | null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type AuthContextOptions = {
|
|
23
|
+
storage?: 'localStorage' | 'sessionStorage' | 'cookie'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Factory to create AuthProvider and typed useAuth hook
|
|
28
|
+
*/
|
|
29
|
+
export function createAuthContext<UserType>(options?: AuthContextOptions) {
|
|
30
|
+
const AuthContext = createContext<AuthContextType<UserType> | null>(null)
|
|
31
|
+
|
|
32
|
+
const AuthProvider = ({ children }: { children: ReactNode }) => {
|
|
33
|
+
const storageType = options?.storage || 'cookie'
|
|
34
|
+
|
|
35
|
+
// Configure token manager once on mount
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
configureTokenManager({ storage: storageType })
|
|
38
|
+
}, [storageType])
|
|
39
|
+
|
|
40
|
+
// ✅ Hooks must be called inside component
|
|
41
|
+
const manager = useTokenManager()
|
|
42
|
+
|
|
43
|
+
const [loading, setLoading] = useState(true)
|
|
44
|
+
|
|
45
|
+
const rawUser = useAuthStore((state) => state.user)
|
|
46
|
+
const error = useAuthStore((state) => state.error)
|
|
47
|
+
const user = rawUser as UserType | null
|
|
48
|
+
|
|
49
|
+
// Restore saved user from token manager
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const savedUser = manager.getSingleToken('user')
|
|
52
|
+
if (savedUser) {
|
|
53
|
+
try {
|
|
54
|
+
const parsedUser = JSON.parse(savedUser)
|
|
55
|
+
useAuthStore.getState().setUser(parsedUser)
|
|
56
|
+
useAuthStore.getState().setError(null)
|
|
57
|
+
} catch {
|
|
58
|
+
useAuthStore.getState().resetAuth()
|
|
59
|
+
useAuthStore.getState().setError(
|
|
60
|
+
new Error('Failed to parse saved user')
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
setLoading(false)
|
|
65
|
+
}, [manager])
|
|
66
|
+
|
|
67
|
+
const setUser = (userData: UserType) => {
|
|
68
|
+
useAuthStore.getState().setUser(userData as any)
|
|
69
|
+
useAuthStore.getState().setError(null)
|
|
70
|
+
manager.setTokens({ user: JSON.stringify(userData) })
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const login = (tokens: Record<string, string>, userData: UserType) => {
|
|
74
|
+
try {
|
|
75
|
+
manager.setTokens(tokens)
|
|
76
|
+
setUser(userData)
|
|
77
|
+
} catch (err) {
|
|
78
|
+
useAuthStore.getState().setError(
|
|
79
|
+
err instanceof Error ? err : new Error(String(err))
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const logout = () => {
|
|
85
|
+
try {
|
|
86
|
+
manager.clearTokens()
|
|
87
|
+
useAuthStore.getState().resetAuth()
|
|
88
|
+
} catch (err) {
|
|
89
|
+
useAuthStore.getState().setError(
|
|
90
|
+
err instanceof Error ? err : new Error(String(err))
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<AuthContext.Provider
|
|
97
|
+
value={{ user, login, logout, setUser, loading, error }}
|
|
98
|
+
>
|
|
99
|
+
{children}
|
|
100
|
+
</AuthContext.Provider>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const useAuth = (): AuthContextType<UserType> => {
|
|
105
|
+
const ctx = useContext(AuthContext)
|
|
106
|
+
if (!ctx) throw new Error('useAuth must be used inside AuthProvider')
|
|
107
|
+
return ctx
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { AuthProvider, useAuth }
|
|
111
|
+
}
|
package/src/RoleGuard.tsx
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useState } from 'react'
|
|
4
|
+
import { useRouter } from 'next/navigation'
|
|
5
|
+
import { auth } from './myAuth'
|
|
6
|
+
|
|
7
|
+
type RoleGuardProps = {
|
|
8
|
+
children: React.ReactNode
|
|
9
|
+
allowedRoles: string[]
|
|
10
|
+
redirectTo?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const RoleGuard: React.FC<RoleGuardProps> = ({
|
|
14
|
+
children,
|
|
15
|
+
allowedRoles,
|
|
16
|
+
redirectTo = '/unauthorized',
|
|
17
|
+
}) => {
|
|
18
|
+
// ✅ Destructure useAuth INSIDE the component
|
|
19
|
+
const { useAuth } = auth
|
|
20
|
+
const { user, loading } = useAuth()
|
|
21
|
+
|
|
22
|
+
const router = useRouter()
|
|
23
|
+
const [isChecking, setIsChecking] = useState(true)
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!user) return
|
|
27
|
+
|
|
28
|
+
const hasAccess = allowedRoles.includes(user?.role)
|
|
29
|
+
if (!hasAccess) {
|
|
30
|
+
router.replace(redirectTo)
|
|
31
|
+
}
|
|
32
|
+
setIsChecking(false)
|
|
33
|
+
}, [user, allowedRoles, redirectTo, router])
|
|
34
|
+
|
|
35
|
+
if (loading || !user || isChecking) return <div>Loading...</div>
|
|
36
|
+
|
|
37
|
+
return <>{children}</>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default RoleGuard
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createAuthContext } from './AuthProvider'
|
|
2
2
|
|
|
3
3
|
export type User = {
|
|
4
4
|
[key: string]: any
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
// Export factory instead of fixed instance
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
export function createAppAuth(
|
|
9
|
+
storage: 'localStorage' | 'sessionStorage' | 'cookie' = 'cookie'
|
|
10
|
+
) {
|
|
11
|
+
return createAuthContext<User>({ storage })
|
|
12
|
+
}
|
|
13
13
|
|
|
14
|
-
export {
|
|
14
|
+
export { createAuthContext } from './AuthProvider'
|
|
15
15
|
export { default as AuthGuard } from './AuthGuard'
|
|
16
|
-
|
|
16
|
+
export { default as RoleGuard } from './RoleGuard'
|
package/src/myAuth.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// myAuth.ts
|
|
2
|
+
'use client'
|
|
3
|
+
import { createAppAuth } from '.'
|
|
4
|
+
export const auth = createAppAuth() // { AuthProvider, useAuth }
|