UNPKG

trainingpeaks-sdk

Version:
127 lines (126 loc) 4.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createTokenRefreshHandler = void 0; const token_1 = require("../../adapters/public-api/endpoints/users/v3/token/index.js"); const domain_1 = require("../../domain/index.js"); const performTokenRefresh = async (currentToken, httpClient, sessionStorage, logger) => { try { logger.info('Starting token refresh', { currentTokenExpires: currentToken.expires, refreshToken: currentToken.refreshToken ? '***' : 'not_available', }); const refreshResponse = await (0, token_1.refreshAuthToken)(httpClient, { refreshToken: currentToken.refreshToken, }); if (!refreshResponse.success || !refreshResponse.data) { logger.error('Token refresh failed - invalid response', { success: refreshResponse.success, hasData: !!refreshResponse.data, error: refreshResponse.error, }); return null; } const tokenData = refreshResponse.data.token; const newToken = (0, domain_1.refreshAuthToken)(currentToken, tokenData.access_token, new Date(tokenData.expires), tokenData.refresh_token); logger.info('Token refresh successful', { oldExpires: currentToken.expires, newExpires: newToken.expires, tokenType: newToken.tokenType, }); const session = await sessionStorage.get(); if (session) { await sessionStorage.set({ ...session, token: newToken, }); logger.debug('Session updated with refreshed token'); } return newToken; } catch (error) { logger.error('Token refresh failed with error', { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, }); return null; } }; const ensureValidToken = async (state, httpClient, sessionStorage, logger) => { try { const session = await sessionStorage.get(); if (!session?.token) { logger.debug('No token found in session'); return null; } const token = session.token; if (!(0, domain_1.shouldRefreshToken)(token) && !(0, domain_1.isTokenExpired)(token)) { return token; } logger.info('Token needs refresh', { isExpired: (0, domain_1.isTokenExpired)(token), shouldRefresh: (0, domain_1.shouldRefreshToken)(token), hasRefreshCapability: (0, domain_1.hasRefreshCapability)(token), }); if (!(0, domain_1.hasRefreshCapability)(token)) { logger.warn('Token cannot be refreshed - no refresh token available'); return null; } if (state.refreshPromise) { logger.debug('Refresh already in progress, waiting for completion'); return await state.refreshPromise; } const now = Date.now(); const currentCooldown = Math.min(30000 * Math.pow(2, state.failureCount), 300000); if (now - state.lastRefreshAttempt < currentCooldown) { logger.warn('Token refresh attempted too recently, skipping', { lastAttempt: state.lastRefreshAttempt, failureCount: state.failureCount, currentCooldown, cooldownRemaining: currentCooldown - (now - state.lastRefreshAttempt), }); return (0, domain_1.isTokenExpired)(token) ? null : token; } state.refreshPromise = performTokenRefresh(token, httpClient, sessionStorage, logger); try { const refreshedToken = await state.refreshPromise; state.lastRefreshAttempt = now; if (refreshedToken) { state.failureCount = 0; } else { state.failureCount++; } return refreshedToken; } catch (error) { state.lastRefreshAttempt = now; state.failureCount++; throw error; } finally { state.refreshPromise = null; } } catch (error) { logger.error('Failed to ensure valid token', { error }); return null; } }; const resetTokenRefreshState = (state) => { state.refreshPromise = null; state.lastRefreshAttempt = 0; }; const createTokenRefreshHandler = (httpClient, sessionStorage, logger) => { const state = { refreshPromise: null, lastRefreshAttempt: 0, failureCount: 0, REFRESH_COOLDOWN: 30000, MAX_BACKOFF: 300000, }; return { ensureValidToken: () => ensureValidToken(state, httpClient, sessionStorage, logger), reset: () => resetTokenRefreshState(state), }; }; exports.createTokenRefreshHandler = createTokenRefreshHandler;