@tern-secure/nextjs 3.2.37 → 3.2.39
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/cjs/boundary/TernSecureClientProvider.js +25 -77
- package/dist/cjs/boundary/TernSecureClientProvider.js.map +1 -1
- package/dist/cjs/boundary/TernSecureCtx.js.map +1 -1
- package/dist/cjs/boundary/hooks/useAuth.js +0 -6
- package/dist/cjs/boundary/hooks/useAuth.js.map +1 -1
- package/dist/esm/boundary/TernSecureClientProvider.js +27 -79
- package/dist/esm/boundary/TernSecureClientProvider.js.map +1 -1
- package/dist/esm/boundary/TernSecureCtx.js.map +1 -1
- package/dist/esm/boundary/hooks/useAuth.js +0 -6
- package/dist/esm/boundary/hooks/useAuth.js.map +1 -1
- package/dist/types/boundary/TernSecureClientProvider.d.ts +1 -1
- package/dist/types/boundary/TernSecureClientProvider.d.ts.map +1 -1
- package/dist/types/boundary/TernSecureCtx.d.ts +1 -2
- package/dist/types/boundary/TernSecureCtx.d.ts.map +1 -1
- package/dist/types/boundary/hooks/useAuth.d.ts +1 -2
- package/dist/types/boundary/hooks/useAuth.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -28,17 +28,13 @@ var import_client_init = require("../utils/client-init");
|
|
|
28
28
|
var import_auth = require("firebase/auth");
|
|
29
29
|
var import_TernSecureCtx = require("./TernSecureCtx");
|
|
30
30
|
var import_navigation = require("next/navigation");
|
|
31
|
-
var import_sessionTernSecure = require("../app-router/server/sessionTernSecure");
|
|
32
31
|
function TernSecureClientProvider({
|
|
33
32
|
children,
|
|
34
|
-
onUserChanged,
|
|
35
33
|
loginPath = "/sign-in",
|
|
36
34
|
loadingComponent
|
|
37
35
|
}) {
|
|
38
36
|
const auth = (0, import_react.useMemo)(() => import_client_init.ternSecureAuth, []);
|
|
39
37
|
const router = (0, import_navigation.useRouter)();
|
|
40
|
-
const pathname = (0, import_navigation.usePathname)();
|
|
41
|
-
const intervalRef = (0, import_react.useRef)(null);
|
|
42
38
|
const [authState, setAuthState] = (0, import_react.useState)(() => ({
|
|
43
39
|
userId: null,
|
|
44
40
|
isLoaded: false,
|
|
@@ -47,10 +43,6 @@ function TernSecureClientProvider({
|
|
|
47
43
|
token: null
|
|
48
44
|
}));
|
|
49
45
|
const handleSignOut = (0, import_react.useCallback)(async (error) => {
|
|
50
|
-
if (intervalRef.current) {
|
|
51
|
-
clearInterval(intervalRef.current);
|
|
52
|
-
intervalRef.current = null;
|
|
53
|
-
}
|
|
54
46
|
await auth.signOut();
|
|
55
47
|
setAuthState({
|
|
56
48
|
isLoaded: true,
|
|
@@ -61,80 +53,36 @@ function TernSecureClientProvider({
|
|
|
61
53
|
});
|
|
62
54
|
router.push(loginPath);
|
|
63
55
|
}, [auth, router, loginPath]);
|
|
64
|
-
const checkTokenValidity = (0, import_react.useCallback)(async (user) => {
|
|
65
|
-
if (user) {
|
|
66
|
-
try {
|
|
67
|
-
const token = await user.getIdToken(true);
|
|
68
|
-
const decodedToken = await (0, import_sessionTernSecure.verifyTernIdToken)(token);
|
|
69
|
-
const isValid = decodedToken.valid;
|
|
70
|
-
if (isValid) {
|
|
71
|
-
return { isValid: true, token, userId: user.uid };
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
console.error("Token validation error:", error);
|
|
75
|
-
await handleSignOut(error instanceof Error ? error : new Error("Authentication token is invalid"));
|
|
76
|
-
return { isValid: false, token: null, userId: null };
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return { isValid: false, token: null, userId: null };
|
|
80
|
-
}, [handleSignOut]);
|
|
81
|
-
const startTokenCheckInterval = (0, import_react.useCallback)(() => {
|
|
82
|
-
if (intervalRef.current) {
|
|
83
|
-
clearInterval(intervalRef.current);
|
|
84
|
-
}
|
|
85
|
-
if (pathname !== loginPath) {
|
|
86
|
-
intervalRef.current = setInterval(() => {
|
|
87
|
-
checkTokenValidity(auth.currentUser);
|
|
88
|
-
}, 3e4);
|
|
89
|
-
}
|
|
90
|
-
}, [auth, checkTokenValidity, loginPath, pathname]);
|
|
91
|
-
const handleAuthStateChange = (0, import_react.useCallback)(async (user) => {
|
|
92
|
-
try {
|
|
93
|
-
const { isValid, token, userId } = await checkTokenValidity(user);
|
|
94
|
-
setAuthState({
|
|
95
|
-
isLoaded: true,
|
|
96
|
-
userId,
|
|
97
|
-
isValid,
|
|
98
|
-
token,
|
|
99
|
-
error: null
|
|
100
|
-
});
|
|
101
|
-
if (onUserChanged) {
|
|
102
|
-
await onUserChanged(user);
|
|
103
|
-
}
|
|
104
|
-
if (!isValid && pathname !== loginPath) {
|
|
105
|
-
router.push(loginPath);
|
|
106
|
-
}
|
|
107
|
-
if (user && isValid) {
|
|
108
|
-
startTokenCheckInterval();
|
|
109
|
-
} else if (intervalRef.current) {
|
|
110
|
-
clearInterval(intervalRef.current);
|
|
111
|
-
intervalRef.current = null;
|
|
112
|
-
}
|
|
113
|
-
} catch (error) {
|
|
114
|
-
console.error("Auth state change error:", error);
|
|
115
|
-
setAuthState({
|
|
116
|
-
isLoaded: true,
|
|
117
|
-
userId: null,
|
|
118
|
-
isValid: false,
|
|
119
|
-
token: null,
|
|
120
|
-
error: error instanceof Error ? error : new Error("An unknown error occurred")
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}, [checkTokenValidity, onUserChanged, router, loginPath, pathname, startTokenCheckInterval]);
|
|
124
56
|
(0, import_react.useEffect)(() => {
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
57
|
+
const unsubscribe = (0, import_auth.onAuthStateChanged)(auth, async (user) => {
|
|
58
|
+
if (user) {
|
|
59
|
+
await user.getIdToken();
|
|
60
|
+
setAuthState({
|
|
61
|
+
isLoaded: true,
|
|
62
|
+
userId: user.uid,
|
|
63
|
+
isValid: true,
|
|
64
|
+
token: user.getIdToken(),
|
|
65
|
+
error: null
|
|
66
|
+
});
|
|
67
|
+
} else {
|
|
68
|
+
setAuthState({
|
|
69
|
+
isLoaded: true,
|
|
70
|
+
userId: null,
|
|
71
|
+
isValid: false,
|
|
72
|
+
token: null,
|
|
73
|
+
error: new Error("User is not authenticated")
|
|
74
|
+
});
|
|
75
|
+
router.push(loginPath);
|
|
130
76
|
}
|
|
131
|
-
}
|
|
132
|
-
|
|
77
|
+
}, (error) => {
|
|
78
|
+
handleSignOut(error instanceof Error ? error : new Error("Authentication error occurred"));
|
|
79
|
+
});
|
|
80
|
+
return () => unsubscribe();
|
|
81
|
+
}, []);
|
|
133
82
|
const contextValue = (0, import_react.useMemo)(() => ({
|
|
134
83
|
...authState,
|
|
135
|
-
checkTokenValidity: () => handleAuthStateChange(auth.currentUser),
|
|
136
84
|
signOut: handleSignOut
|
|
137
|
-
}), [authState,
|
|
85
|
+
}), [authState, auth, handleSignOut]);
|
|
138
86
|
if (!authState.isLoaded) {
|
|
139
87
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TernSecureCtx.TernSecureCtx.Provider, { value: contextValue, children: loadingComponent || /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "aria-live": "polite", "aria-busy": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only", children: "Loading authentication state..." }) }) });
|
|
140
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport React, { useState, useEffect, useMemo, useCallback
|
|
1
|
+
{"version":3,"sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport React, { useState, useEffect, useMemo, useCallback } from 'react'\r\nimport { ternSecureAuth } from '../utils/client-init'\r\nimport { onAuthStateChanged, User } from \"firebase/auth\"\r\nimport { TernSecureCtx, TernSecureCtxValue, TernSecureState } from './TernSecureCtx'\r\nimport { useRouter } from 'next/navigation'\r\n\r\ninterface TernSecureClientProviderProps {\r\n children: React.ReactNode;\r\n onUserChanged?: (user: User | null) => Promise<void>;\r\n loginPath?: string;\r\n loadingComponent?: React.ReactNode;\r\n}\r\n\r\nexport function TernSecureClientProvider({ \r\n children, \r\n loginPath = '/sign-in',\r\n loadingComponent\r\n}: TernSecureClientProviderProps) {\r\n const auth = useMemo(() => ternSecureAuth, []);\r\n const router = useRouter();\r\n const [authState, setAuthState] = useState<TernSecureState>(() => ({\r\n userId: null,\r\n isLoaded: false,\r\n error: null,\r\n isValid: false,\r\n token: null\r\n }));\r\n\r\n const handleSignOut = useCallback(async (error?: Error) => {\r\n await auth.signOut();\r\n setAuthState({\r\n isLoaded: true,\r\n userId: null,\r\n error: error || null,\r\n isValid: false,\r\n token: null\r\n });\r\n router.push(loginPath);\r\n }, [auth, router, loginPath]);\r\n\r\nuseEffect(() => {\r\n const unsubscribe = onAuthStateChanged(auth, async (user: User | null) => {\r\n if (user) {\r\n await user.getIdToken()\r\n setAuthState({\r\n isLoaded: true,\r\n userId: user.uid,\r\n isValid: true,\r\n token: user.getIdToken(),\r\n error: null\r\n })\r\n } else {\r\n setAuthState({\r\n isLoaded: true,\r\n userId: null,\r\n isValid: false,\r\n token: null,\r\n error: new Error('User is not authenticated')\r\n })\r\n router.push(loginPath);\r\n }\r\n }, (error) => {\r\n handleSignOut(error instanceof Error ? error : new Error('Authentication error occurred'));\r\n })\r\n \r\n return () => unsubscribe()\r\n }, [])\r\n\r\n const contextValue: TernSecureCtxValue = useMemo(() => ({\r\n ...authState,\r\n signOut: handleSignOut,\r\n }), [authState, auth, handleSignOut]);\r\n\r\n if (!authState.isLoaded) {\r\n return (\r\n <TernSecureCtx.Provider value={contextValue}>\r\n {loadingComponent || (\r\n <div aria-live=\"polite\" aria-busy=\"true\">\r\n <span className=\"sr-only\">Loading authentication state...</span>\r\n </div>\r\n )}\r\n </TernSecureCtx.Provider>\r\n );\r\n }\r\n\r\n return (\r\n <TernSecureCtx.Provider value={contextValue}>\r\n {children}\r\n </TernSecureCtx.Provider>\r\n )\r\n}"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgFY;AA9EZ,mBAAiE;AACjE,yBAA+B;AAC/B,kBAAyC;AACzC,2BAAmE;AACnE,wBAA0B;AASnB,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAAkC;AAChC,QAAM,WAAO,sBAAQ,MAAM,mCAAgB,CAAC,CAAC;AAC7C,QAAM,aAAS,6BAAU;AACzB,QAAM,CAAC,WAAW,YAAY,QAAI,uBAA0B,OAAO;AAAA,IACjE,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,OAAO;AAAA,EACT,EAAE;AAEF,QAAM,oBAAgB,0BAAY,OAAO,UAAkB;AACzD,UAAM,KAAK,QAAQ;AACnB,iBAAa;AAAA,MACX,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,OAAO;AAAA,IACT,CAAC;AACD,WAAO,KAAK,SAAS;AAAA,EACvB,GAAG,CAAC,MAAM,QAAQ,SAAS,CAAC;AAE9B,8BAAU,MAAM;AACZ,UAAM,kBAAc,gCAAmB,MAAM,OAAO,SAAsB;AACxE,UAAI,MAAM;AACR,cAAM,KAAK,WAAW;AACtB,qBAAa;AAAA,UACX,UAAU;AAAA,UACV,QAAQ,KAAK;AAAA,UACb,SAAS;AAAA,UACT,OAAO,KAAK,WAAW;AAAA,UACvB,OAAO;AAAA,QACT,CAAC;AAAA,MACH,OAAO;AACL,qBAAa;AAAA,UACX,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,OAAO;AAAA,UACP,OAAO,IAAI,MAAM,2BAA2B;AAAA,QAC9C,CAAC;AACD,eAAO,KAAK,SAAS;AAAA,MACvB;AAAA,IACF,GAAG,CAAC,UAAU;AACZ,oBAAc,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,+BAA+B,CAAC;AAAA,IAC3F,CAAC;AAED,WAAO,MAAM,YAAY;AAAA,EAC3B,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmC,sBAAQ,OAAO;AAAA,IACtD,GAAG;AAAA,IACH,SAAS;AAAA,EACX,IAAI,CAAC,WAAW,MAAM,aAAa,CAAC;AAEpC,MAAI,CAAC,UAAU,UAAU;AACvB,WACE,4CAAC,mCAAc,UAAd,EAAuB,OAAO,cAC5B,8BACC,4CAAC,SAAI,aAAU,UAAS,aAAU,QAChC,sDAAC,UAAK,WAAU,WAAU,6CAA+B,GAC3D,GAEJ;AAAA,EAEJ;AAEA,SACI,4CAAC,mCAAc,UAAd,EAAuB,OAAO,cAC7B,UACF;AAEN;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/boundary/TernSecureCtx.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { createContext, useContext } from 'react'\r\nimport { ternSecureAuth } from '../utils/client-init';\r\nimport { User } from 'firebase/auth';\r\n\r\nexport const TernSecureUser = (): User | null => {\r\n return ternSecureAuth.currentUser;\r\n}\r\n\r\nexport interface TernSecureState {\r\n userId: string | null\r\n isLoaded: boolean\r\n error: Error | null\r\n isValid: boolean\r\n token:
|
|
1
|
+
{"version":3,"sources":["../../../src/boundary/TernSecureCtx.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { createContext, useContext } from 'react'\r\nimport { ternSecureAuth } from '../utils/client-init';\r\nimport { User } from 'firebase/auth';\r\n\r\nexport const TernSecureUser = (): User | null => {\r\n return ternSecureAuth.currentUser;\r\n}\r\n\r\nexport interface TernSecureState {\r\n userId: string | null\r\n isLoaded: boolean\r\n error: Error | null\r\n isValid: boolean\r\n token: any | null\r\n}\r\n\r\nexport interface TernSecureCtxValue extends TernSecureState {\r\n //checkTokenValidity: () => Promise<void>;\r\n signOut: () => Promise<void>;\r\n}\r\n\r\nexport const TernSecureCtx = createContext<TernSecureCtxValue | null>(null)\r\n\r\nTernSecureCtx.displayName = 'TernSecureCtx'\r\n\r\nexport const useTernSecure = (hookName: string) => {\r\n const context = useContext(TernSecureCtx)\r\n \r\n if (!context) {\r\n throw new Error(\r\n `${hookName} must be used within TernSecureProvider`\r\n )\r\n }\r\n\r\n return context\r\n}\r\n\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,mBAA0C;AAC1C,yBAA+B;AAGxB,MAAM,iBAAiB,MAAmB;AAC/C,SAAO,kCAAe;AACxB;AAeO,MAAM,oBAAgB,4BAAyC,IAAI;AAE1E,cAAc,cAAc;AAErB,MAAM,gBAAgB,CAAC,aAAqB;AACjD,QAAM,cAAU,yBAAW,aAAa;AAExC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -22,7 +22,6 @@ __export(useAuth_exports, {
|
|
|
22
22
|
useAuth: () => useAuth
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(useAuth_exports);
|
|
25
|
-
var import_react = require("react");
|
|
26
25
|
var import_TernSecureCtx = require("../TernSecureCtx");
|
|
27
26
|
var import_TernSecureCtx2 = require("../TernSecureCtx");
|
|
28
27
|
function useAuth() {
|
|
@@ -32,13 +31,9 @@ function useAuth() {
|
|
|
32
31
|
error,
|
|
33
32
|
isValid,
|
|
34
33
|
token,
|
|
35
|
-
checkTokenValidity,
|
|
36
34
|
signOut
|
|
37
35
|
} = (0, import_TernSecureCtx.useTernSecure)("useAuth");
|
|
38
36
|
const user = (0, import_TernSecureCtx2.TernSecureUser)();
|
|
39
|
-
const refreshToken = (0, import_react.useCallback)(async () => {
|
|
40
|
-
await checkTokenValidity();
|
|
41
|
-
}, [checkTokenValidity]);
|
|
42
37
|
return {
|
|
43
38
|
user,
|
|
44
39
|
userId,
|
|
@@ -46,7 +41,6 @@ function useAuth() {
|
|
|
46
41
|
error,
|
|
47
42
|
isAuthenticated: isValid,
|
|
48
43
|
token,
|
|
49
|
-
refreshToken,
|
|
50
44
|
signOut
|
|
51
45
|
};
|
|
52
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/boundary/hooks/useAuth.ts"],"sourcesContent":["\"use client\"\r\n\r\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/boundary/hooks/useAuth.ts"],"sourcesContent":["\"use client\"\r\n\r\nimport { useTernSecure } from '../TernSecureCtx'\r\nimport { User } from 'firebase/auth'\r\nimport { TernSecureUser } from '../TernSecureCtx'\r\n\r\nexport function useAuth() {\r\n const {\r\n userId,\r\n isLoaded,\r\n error,\r\n isValid,\r\n token,\r\n signOut\r\n } = useTernSecure('useAuth')\r\n\r\n const user: User | null = TernSecureUser()\r\n\r\n\r\n return {\r\n user,\r\n userId,\r\n isLoaded,\r\n error,\r\n isAuthenticated: isValid,\r\n token,\r\n signOut\r\n }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,2BAA8B;AAE9B,IAAAA,wBAA+B;AAExB,SAAS,UAAU;AACxB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,QAAI,oCAAc,SAAS;AAE3B,QAAM,WAAoB,sCAAe;AAGzC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACF;","names":["import_TernSecureCtx"]}
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useEffect, useMemo, useCallback
|
|
3
|
+
import { useState, useEffect, useMemo, useCallback } from "react";
|
|
4
4
|
import { ternSecureAuth } from "../utils/client-init";
|
|
5
5
|
import { onAuthStateChanged } from "firebase/auth";
|
|
6
6
|
import { TernSecureCtx } from "./TernSecureCtx";
|
|
7
|
-
import { useRouter
|
|
8
|
-
import { verifyTernIdToken } from "../app-router/server/sessionTernSecure";
|
|
7
|
+
import { useRouter } from "next/navigation";
|
|
9
8
|
function TernSecureClientProvider({
|
|
10
9
|
children,
|
|
11
|
-
onUserChanged,
|
|
12
10
|
loginPath = "/sign-in",
|
|
13
11
|
loadingComponent
|
|
14
12
|
}) {
|
|
15
13
|
const auth = useMemo(() => ternSecureAuth, []);
|
|
16
14
|
const router = useRouter();
|
|
17
|
-
const pathname = usePathname();
|
|
18
|
-
const intervalRef = useRef(null);
|
|
19
15
|
const [authState, setAuthState] = useState(() => ({
|
|
20
16
|
userId: null,
|
|
21
17
|
isLoaded: false,
|
|
@@ -24,10 +20,6 @@ function TernSecureClientProvider({
|
|
|
24
20
|
token: null
|
|
25
21
|
}));
|
|
26
22
|
const handleSignOut = useCallback(async (error) => {
|
|
27
|
-
if (intervalRef.current) {
|
|
28
|
-
clearInterval(intervalRef.current);
|
|
29
|
-
intervalRef.current = null;
|
|
30
|
-
}
|
|
31
23
|
await auth.signOut();
|
|
32
24
|
setAuthState({
|
|
33
25
|
isLoaded: true,
|
|
@@ -38,80 +30,36 @@ function TernSecureClientProvider({
|
|
|
38
30
|
});
|
|
39
31
|
router.push(loginPath);
|
|
40
32
|
}, [auth, router, loginPath]);
|
|
41
|
-
const checkTokenValidity = useCallback(async (user) => {
|
|
42
|
-
if (user) {
|
|
43
|
-
try {
|
|
44
|
-
const token = await user.getIdToken(true);
|
|
45
|
-
const decodedToken = await verifyTernIdToken(token);
|
|
46
|
-
const isValid = decodedToken.valid;
|
|
47
|
-
if (isValid) {
|
|
48
|
-
return { isValid: true, token, userId: user.uid };
|
|
49
|
-
}
|
|
50
|
-
} catch (error) {
|
|
51
|
-
console.error("Token validation error:", error);
|
|
52
|
-
await handleSignOut(error instanceof Error ? error : new Error("Authentication token is invalid"));
|
|
53
|
-
return { isValid: false, token: null, userId: null };
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return { isValid: false, token: null, userId: null };
|
|
57
|
-
}, [handleSignOut]);
|
|
58
|
-
const startTokenCheckInterval = useCallback(() => {
|
|
59
|
-
if (intervalRef.current) {
|
|
60
|
-
clearInterval(intervalRef.current);
|
|
61
|
-
}
|
|
62
|
-
if (pathname !== loginPath) {
|
|
63
|
-
intervalRef.current = setInterval(() => {
|
|
64
|
-
checkTokenValidity(auth.currentUser);
|
|
65
|
-
}, 3e4);
|
|
66
|
-
}
|
|
67
|
-
}, [auth, checkTokenValidity, loginPath, pathname]);
|
|
68
|
-
const handleAuthStateChange = useCallback(async (user) => {
|
|
69
|
-
try {
|
|
70
|
-
const { isValid, token, userId } = await checkTokenValidity(user);
|
|
71
|
-
setAuthState({
|
|
72
|
-
isLoaded: true,
|
|
73
|
-
userId,
|
|
74
|
-
isValid,
|
|
75
|
-
token,
|
|
76
|
-
error: null
|
|
77
|
-
});
|
|
78
|
-
if (onUserChanged) {
|
|
79
|
-
await onUserChanged(user);
|
|
80
|
-
}
|
|
81
|
-
if (!isValid && pathname !== loginPath) {
|
|
82
|
-
router.push(loginPath);
|
|
83
|
-
}
|
|
84
|
-
if (user && isValid) {
|
|
85
|
-
startTokenCheckInterval();
|
|
86
|
-
} else if (intervalRef.current) {
|
|
87
|
-
clearInterval(intervalRef.current);
|
|
88
|
-
intervalRef.current = null;
|
|
89
|
-
}
|
|
90
|
-
} catch (error) {
|
|
91
|
-
console.error("Auth state change error:", error);
|
|
92
|
-
setAuthState({
|
|
93
|
-
isLoaded: true,
|
|
94
|
-
userId: null,
|
|
95
|
-
isValid: false,
|
|
96
|
-
token: null,
|
|
97
|
-
error: error instanceof Error ? error : new Error("An unknown error occurred")
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
}, [checkTokenValidity, onUserChanged, router, loginPath, pathname, startTokenCheckInterval]);
|
|
101
33
|
useEffect(() => {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
34
|
+
const unsubscribe = onAuthStateChanged(auth, async (user) => {
|
|
35
|
+
if (user) {
|
|
36
|
+
await user.getIdToken();
|
|
37
|
+
setAuthState({
|
|
38
|
+
isLoaded: true,
|
|
39
|
+
userId: user.uid,
|
|
40
|
+
isValid: true,
|
|
41
|
+
token: user.getIdToken(),
|
|
42
|
+
error: null
|
|
43
|
+
});
|
|
44
|
+
} else {
|
|
45
|
+
setAuthState({
|
|
46
|
+
isLoaded: true,
|
|
47
|
+
userId: null,
|
|
48
|
+
isValid: false,
|
|
49
|
+
token: null,
|
|
50
|
+
error: new Error("User is not authenticated")
|
|
51
|
+
});
|
|
52
|
+
router.push(loginPath);
|
|
107
53
|
}
|
|
108
|
-
}
|
|
109
|
-
|
|
54
|
+
}, (error) => {
|
|
55
|
+
handleSignOut(error instanceof Error ? error : new Error("Authentication error occurred"));
|
|
56
|
+
});
|
|
57
|
+
return () => unsubscribe();
|
|
58
|
+
}, []);
|
|
110
59
|
const contextValue = useMemo(() => ({
|
|
111
60
|
...authState,
|
|
112
|
-
checkTokenValidity: () => handleAuthStateChange(auth.currentUser),
|
|
113
61
|
signOut: handleSignOut
|
|
114
|
-
}), [authState,
|
|
62
|
+
}), [authState, auth, handleSignOut]);
|
|
115
63
|
if (!authState.isLoaded) {
|
|
116
64
|
return /* @__PURE__ */ jsx(TernSecureCtx.Provider, { value: contextValue, children: loadingComponent || /* @__PURE__ */ jsx("div", { "aria-live": "polite", "aria-busy": "true", children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading authentication state..." }) }) });
|
|
117
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport React, { useState, useEffect, useMemo, useCallback
|
|
1
|
+
{"version":3,"sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport React, { useState, useEffect, useMemo, useCallback } from 'react'\r\nimport { ternSecureAuth } from '../utils/client-init'\r\nimport { onAuthStateChanged, User } from \"firebase/auth\"\r\nimport { TernSecureCtx, TernSecureCtxValue, TernSecureState } from './TernSecureCtx'\r\nimport { useRouter } from 'next/navigation'\r\n\r\ninterface TernSecureClientProviderProps {\r\n children: React.ReactNode;\r\n onUserChanged?: (user: User | null) => Promise<void>;\r\n loginPath?: string;\r\n loadingComponent?: React.ReactNode;\r\n}\r\n\r\nexport function TernSecureClientProvider({ \r\n children, \r\n loginPath = '/sign-in',\r\n loadingComponent\r\n}: TernSecureClientProviderProps) {\r\n const auth = useMemo(() => ternSecureAuth, []);\r\n const router = useRouter();\r\n const [authState, setAuthState] = useState<TernSecureState>(() => ({\r\n userId: null,\r\n isLoaded: false,\r\n error: null,\r\n isValid: false,\r\n token: null\r\n }));\r\n\r\n const handleSignOut = useCallback(async (error?: Error) => {\r\n await auth.signOut();\r\n setAuthState({\r\n isLoaded: true,\r\n userId: null,\r\n error: error || null,\r\n isValid: false,\r\n token: null\r\n });\r\n router.push(loginPath);\r\n }, [auth, router, loginPath]);\r\n\r\nuseEffect(() => {\r\n const unsubscribe = onAuthStateChanged(auth, async (user: User | null) => {\r\n if (user) {\r\n await user.getIdToken()\r\n setAuthState({\r\n isLoaded: true,\r\n userId: user.uid,\r\n isValid: true,\r\n token: user.getIdToken(),\r\n error: null\r\n })\r\n } else {\r\n setAuthState({\r\n isLoaded: true,\r\n userId: null,\r\n isValid: false,\r\n token: null,\r\n error: new Error('User is not authenticated')\r\n })\r\n router.push(loginPath);\r\n }\r\n }, (error) => {\r\n handleSignOut(error instanceof Error ? error : new Error('Authentication error occurred'));\r\n })\r\n \r\n return () => unsubscribe()\r\n }, [])\r\n\r\n const contextValue: TernSecureCtxValue = useMemo(() => ({\r\n ...authState,\r\n signOut: handleSignOut,\r\n }), [authState, auth, handleSignOut]);\r\n\r\n if (!authState.isLoaded) {\r\n return (\r\n <TernSecureCtx.Provider value={contextValue}>\r\n {loadingComponent || (\r\n <div aria-live=\"polite\" aria-busy=\"true\">\r\n <span className=\"sr-only\">Loading authentication state...</span>\r\n </div>\r\n )}\r\n </TernSecureCtx.Provider>\r\n );\r\n }\r\n\r\n return (\r\n <TernSecureCtx.Provider value={contextValue}>\r\n {children}\r\n </TernSecureCtx.Provider>\r\n )\r\n}"],"mappings":";AAgFY;AA9EZ,SAAgB,UAAU,WAAW,SAAS,mBAAmB;AACjE,SAAS,sBAAsB;AAC/B,SAAS,0BAAgC;AACzC,SAAS,qBAA0D;AACnE,SAAS,iBAAiB;AASnB,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAAkC;AAChC,QAAM,OAAO,QAAQ,MAAM,gBAAgB,CAAC,CAAC;AAC7C,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,WAAW,YAAY,IAAI,SAA0B,OAAO;AAAA,IACjE,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,OAAO;AAAA,EACT,EAAE;AAEF,QAAM,gBAAgB,YAAY,OAAO,UAAkB;AACzD,UAAM,KAAK,QAAQ;AACnB,iBAAa;AAAA,MACX,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,OAAO;AAAA,IACT,CAAC;AACD,WAAO,KAAK,SAAS;AAAA,EACvB,GAAG,CAAC,MAAM,QAAQ,SAAS,CAAC;AAE9B,YAAU,MAAM;AACZ,UAAM,cAAc,mBAAmB,MAAM,OAAO,SAAsB;AACxE,UAAI,MAAM;AACR,cAAM,KAAK,WAAW;AACtB,qBAAa;AAAA,UACX,UAAU;AAAA,UACV,QAAQ,KAAK;AAAA,UACb,SAAS;AAAA,UACT,OAAO,KAAK,WAAW;AAAA,UACvB,OAAO;AAAA,QACT,CAAC;AAAA,MACH,OAAO;AACL,qBAAa;AAAA,UACX,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,OAAO;AAAA,UACP,OAAO,IAAI,MAAM,2BAA2B;AAAA,QAC9C,CAAC;AACD,eAAO,KAAK,SAAS;AAAA,MACvB;AAAA,IACF,GAAG,CAAC,UAAU;AACZ,oBAAc,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,+BAA+B,CAAC;AAAA,IAC3F,CAAC;AAED,WAAO,MAAM,YAAY;AAAA,EAC3B,GAAG,CAAC,CAAC;AAEL,QAAM,eAAmC,QAAQ,OAAO;AAAA,IACtD,GAAG;AAAA,IACH,SAAS;AAAA,EACX,IAAI,CAAC,WAAW,MAAM,aAAa,CAAC;AAEpC,MAAI,CAAC,UAAU,UAAU;AACvB,WACE,oBAAC,cAAc,UAAd,EAAuB,OAAO,cAC5B,8BACC,oBAAC,SAAI,aAAU,UAAS,aAAU,QAChC,8BAAC,UAAK,WAAU,WAAU,6CAA+B,GAC3D,GAEJ;AAAA,EAEJ;AAEA,SACI,oBAAC,cAAc,UAAd,EAAuB,OAAO,cAC7B,UACF;AAEN;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/boundary/TernSecureCtx.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { createContext, useContext } from 'react'\r\nimport { ternSecureAuth } from '../utils/client-init';\r\nimport { User } from 'firebase/auth';\r\n\r\nexport const TernSecureUser = (): User | null => {\r\n return ternSecureAuth.currentUser;\r\n}\r\n\r\nexport interface TernSecureState {\r\n userId: string | null\r\n isLoaded: boolean\r\n error: Error | null\r\n isValid: boolean\r\n token:
|
|
1
|
+
{"version":3,"sources":["../../../src/boundary/TernSecureCtx.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { createContext, useContext } from 'react'\r\nimport { ternSecureAuth } from '../utils/client-init';\r\nimport { User } from 'firebase/auth';\r\n\r\nexport const TernSecureUser = (): User | null => {\r\n return ternSecureAuth.currentUser;\r\n}\r\n\r\nexport interface TernSecureState {\r\n userId: string | null\r\n isLoaded: boolean\r\n error: Error | null\r\n isValid: boolean\r\n token: any | null\r\n}\r\n\r\nexport interface TernSecureCtxValue extends TernSecureState {\r\n //checkTokenValidity: () => Promise<void>;\r\n signOut: () => Promise<void>;\r\n}\r\n\r\nexport const TernSecureCtx = createContext<TernSecureCtxValue | null>(null)\r\n\r\nTernSecureCtx.displayName = 'TernSecureCtx'\r\n\r\nexport const useTernSecure = (hookName: string) => {\r\n const context = useContext(TernSecureCtx)\r\n \r\n if (!context) {\r\n throw new Error(\r\n `${hookName} must be used within TernSecureProvider`\r\n )\r\n }\r\n\r\n return context\r\n}\r\n\r\n"],"mappings":";AAEA,SAAS,eAAe,kBAAkB;AAC1C,SAAS,sBAAsB;AAGxB,MAAM,iBAAiB,MAAmB;AAC/C,SAAO,eAAe;AACxB;AAeO,MAAM,gBAAgB,cAAyC,IAAI;AAE1E,cAAc,cAAc;AAErB,MAAM,gBAAgB,CAAC,aAAqB;AACjD,QAAM,UAAU,WAAW,aAAa;AAExC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useCallback } from "react";
|
|
3
2
|
import { useTernSecure } from "../TernSecureCtx";
|
|
4
3
|
import { TernSecureUser } from "../TernSecureCtx";
|
|
5
4
|
function useAuth() {
|
|
@@ -9,13 +8,9 @@ function useAuth() {
|
|
|
9
8
|
error,
|
|
10
9
|
isValid,
|
|
11
10
|
token,
|
|
12
|
-
checkTokenValidity,
|
|
13
11
|
signOut
|
|
14
12
|
} = useTernSecure("useAuth");
|
|
15
13
|
const user = TernSecureUser();
|
|
16
|
-
const refreshToken = useCallback(async () => {
|
|
17
|
-
await checkTokenValidity();
|
|
18
|
-
}, [checkTokenValidity]);
|
|
19
14
|
return {
|
|
20
15
|
user,
|
|
21
16
|
userId,
|
|
@@ -23,7 +18,6 @@ function useAuth() {
|
|
|
23
18
|
error,
|
|
24
19
|
isAuthenticated: isValid,
|
|
25
20
|
token,
|
|
26
|
-
refreshToken,
|
|
27
21
|
signOut
|
|
28
22
|
};
|
|
29
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/boundary/hooks/useAuth.ts"],"sourcesContent":["\"use client\"\r\n\r\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/boundary/hooks/useAuth.ts"],"sourcesContent":["\"use client\"\r\n\r\nimport { useTernSecure } from '../TernSecureCtx'\r\nimport { User } from 'firebase/auth'\r\nimport { TernSecureUser } from '../TernSecureCtx'\r\n\r\nexport function useAuth() {\r\n const {\r\n userId,\r\n isLoaded,\r\n error,\r\n isValid,\r\n token,\r\n signOut\r\n } = useTernSecure('useAuth')\r\n\r\n const user: User | null = TernSecureUser()\r\n\r\n\r\n return {\r\n user,\r\n userId,\r\n isLoaded,\r\n error,\r\n isAuthenticated: isValid,\r\n token,\r\n signOut\r\n }\r\n}\r\n"],"mappings":";AAEA,SAAS,qBAAqB;AAE9B,SAAS,sBAAsB;AAExB,SAAS,UAAU;AACxB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,cAAc,SAAS;AAE3B,QAAM,OAAoB,eAAe;AAGzC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
@@ -6,6 +6,6 @@ interface TernSecureClientProviderProps {
|
|
|
6
6
|
loginPath?: string;
|
|
7
7
|
loadingComponent?: React.ReactNode;
|
|
8
8
|
}
|
|
9
|
-
export declare function TernSecureClientProvider({ children,
|
|
9
|
+
export declare function TernSecureClientProvider({ children, loginPath, loadingComponent }: TernSecureClientProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
10
10
|
export {};
|
|
11
11
|
//# sourceMappingURL=TernSecureClientProvider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TernSecureClientProvider.d.ts","sourceRoot":"","sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"TernSecureClientProvider.d.ts","sourceRoot":"","sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAoD,MAAM,OAAO,CAAA;AAExE,OAAO,EAAsB,IAAI,EAAE,MAAM,eAAe,CAAA;AAIxD,UAAU,6BAA6B;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CACpC;AAED,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EACR,SAAsB,EACtB,gBAAgB,EACjB,EAAE,6BAA6B,2CAyE/B"}
|
|
@@ -5,10 +5,9 @@ export interface TernSecureState {
|
|
|
5
5
|
isLoaded: boolean;
|
|
6
6
|
error: Error | null;
|
|
7
7
|
isValid: boolean;
|
|
8
|
-
token:
|
|
8
|
+
token: any | null;
|
|
9
9
|
}
|
|
10
10
|
export interface TernSecureCtxValue extends TernSecureState {
|
|
11
|
-
checkTokenValidity: () => Promise<void>;
|
|
12
11
|
signOut: () => Promise<void>;
|
|
13
12
|
}
|
|
14
13
|
export declare const TernSecureCtx: import("react").Context<TernSecureCtxValue | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TernSecureCtx.d.ts","sourceRoot":"","sources":["../../../src/boundary/TernSecureCtx.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,cAAc,QAAO,IAAI,GAAG,IAExC,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"TernSecureCtx.d.ts","sourceRoot":"","sources":["../../../src/boundary/TernSecureCtx.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,eAAO,MAAM,cAAc,QAAO,IAAI,GAAG,IAExC,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,GAAG,GAAG,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,kBAAmB,SAAQ,eAAe;IAEzD,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa,oDAAiD,CAAA;AAI3E,eAAO,MAAM,aAAa,aAAc,MAAM,uBAU7C,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../../../src/boundary/hooks/useAuth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../../../../src/boundary/hooks/useAuth.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AAGpC,wBAAgB,OAAO;;;;;;;;EAsBtB"}
|