Skip to content

Commit 24f5c24

Browse files
committed
refactor(bd-jv5u083l): timer refs to effect-locals; dedupe renewal-failure path
refreshTimer/expiryTimer were only used inside the schedule effect — effect-local variables replace the refs and the redundant top-of-effect clears (cleanup always runs before re-run). The verdict deadline and onError shared a settle+disable sequence, now abandonRenewal. No behavior change; existing tests unchanged.
1 parent 9cd290e commit 24f5c24

1 file changed

Lines changed: 14 additions & 16 deletions

File tree

hub-client/src/hooks/useAuth.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ export function useAuth() {
4949
const [refreshEnabled, setRefreshEnabled] = useState(false);
5050
const [sessionExpired, setSessionExpired] = useState(false);
5151
const isRefreshing = useRef(false);
52-
const refreshTimer = useRef<ReturnType<typeof setTimeout>>(null);
53-
const expiryTimer = useRef<ReturnType<typeof setTimeout>>(null);
5452
const refreshDeadline = useRef<ReturnType<typeof setTimeout>>(null);
5553

5654
// Effective expiry of the current session (0 = no session).
@@ -95,6 +93,12 @@ export function useAuth() {
9593
isRefreshing.current = false;
9694
}, []);
9795

96+
/** Renewal failed without a hub verdict — settle and stand One Tap down. */
97+
const abandonRenewal = useCallback(() => {
98+
settleRefresh();
99+
setRefreshEnabled(false);
100+
}, [settleRefresh]);
101+
98102
// Single entry point for activating One Tap. Coalesces concurrent
99103
// triggers (e.g. N parallel 401s) into one refresh attempt.
100104
const triggerRefresh = useCallback(() => {
@@ -104,11 +108,8 @@ export function useAuth() {
104108
// The IdP may never call back (GIS blocked / FedCM policies). Without a
105109
// deadline, isRefreshing wedges true for the tab's lifetime: the expiry
106110
// re-check never reaches a verdict and refocus/retry are disabled.
107-
refreshDeadline.current = setTimeout(() => {
108-
settleRefresh();
109-
setRefreshEnabled(false);
110-
}, REFRESH_VERDICT_TIMEOUT_MS);
111-
}, [settleRefresh]);
111+
refreshDeadline.current = setTimeout(abandonRenewal, REFRESH_VERDICT_TIMEOUT_MS);
112+
}, [abandonRenewal]);
112113

113114
// Silent renewal via the active AuthProvider. The provider collapses
114115
// "renewal returned no usable credential" into onError, so the consumer
@@ -133,8 +134,7 @@ export function useAuth() {
133134
setRefreshEnabled(false);
134135
},
135136
onError: () => {
136-
settleRefresh();
137-
setRefreshEnabled(false);
137+
abandonRenewal();
138138
if (sessionLapsed()) expireSession();
139139
},
140140
});
@@ -180,9 +180,6 @@ export function useAuth() {
180180
// Schedule silent refresh and an expiry-time server re-check from the
181181
// session's real expiry.
182182
useEffect(() => {
183-
if (refreshTimer.current) clearTimeout(refreshTimer.current);
184-
if (expiryTimer.current) clearTimeout(expiryTimer.current);
185-
186183
if (!auth) {
187184
expiresAtRef.current = 0;
188185
return;
@@ -192,15 +189,16 @@ export function useAuth() {
192189
expiresAtRef.current = expiresAt;
193190

194191
// Silent refresh before expiry; immediately if already inside the buffer.
195-
refreshTimer.current = setTimeout(
192+
const refreshTimer = setTimeout(
196193
triggerRefresh,
197194
Math.max(expiresAt - REFRESH_BUFFER_MS - Date.now(), 0),
198195
);
199196

200197
// Expiry-time re-check. Only a definitive 401/403 clears the session;
201198
// network errors reschedule (logout on evidence, not on schedule).
199+
let expiryTimer: ReturnType<typeof setTimeout>;
202200
const scheduleExpiryCheck = (delay: number) => {
203-
expiryTimer.current = setTimeout(() => {
201+
expiryTimer = setTimeout(() => {
204202
fetchAuthMe()
205203
.then((me) => {
206204
if (me) {
@@ -222,8 +220,8 @@ export function useAuth() {
222220
scheduleExpiryCheck(msUntilExpiry > 0 ? msUntilExpiry + 1000 : EXPIRY_RECHECK_MS);
223221

224222
return () => {
225-
if (refreshTimer.current) clearTimeout(refreshTimer.current);
226-
if (expiryTimer.current) clearTimeout(expiryTimer.current);
223+
clearTimeout(refreshTimer);
224+
clearTimeout(expiryTimer);
227225
};
228226
}, [auth, applyAuth, expireSession, triggerRefresh]);
229227

0 commit comments

Comments
 (0)