UNPKG

trainingpeaks-sdk

Version:
96 lines (95 loc) 4.44 kB
import { throwCookieNotFoundError, throwHttpErrorFromResponse, throwMissingDataError, throwTokenExpiredError, throwValidationError, } from '../../adapters/errors/http-errors.js'; import { mapTPTokenToAuthToken, mapTPUserToUser } from '../../adapters/mappers/index.js'; import { isTokenExpired, validateCredentials, } from '../../domain/index.js'; import { API_ENDPOINTS } from './constants/api-urls.js'; import { getAuthToken, getLoginPage, getRequestVerificationToken, getUser, submitLogin, } from './endpoints/index.js'; const createErrorContext = (url, method, requestData) => ({ url, method, ...(requestData && { requestData }), }); const createLogin = (deps) => { return async (credentials) => { if (!validateCredentials(credentials)) { throwValidationError('Invalid credentials provided', createErrorContext(API_ENDPOINTS.LOGIN_PAGE, 'POST', { username: credentials.username, })); } const response = await getLoginPage(deps.httpClient); if (!response.success) { throwHttpErrorFromResponse(response, 'Get request verification token', createErrorContext(API_ENDPOINTS.LOGIN_PAGE, 'GET')); } if (!response.data) { throwMissingDataError('No response data received from login page', createErrorContext(API_ENDPOINTS.LOGIN_PAGE, 'GET')); } const requestVerificationToken = getRequestVerificationToken(response.data); if (!requestVerificationToken) { throwValidationError('Request verification token not found', createErrorContext(API_ENDPOINTS.LOGIN_PAGE, 'GET')); } const submitLoginResponse = await submitLogin(deps.httpClient, requestVerificationToken, credentials); if (!submitLoginResponse.success) { throwHttpErrorFromResponse(submitLoginResponse, 'Submit login', createErrorContext(API_ENDPOINTS.LOGIN_PAGE, 'POST', { username: credentials.username, })); } const tpAuthCookie = submitLoginResponse.cookies?.find((cookie) => cookie.includes('Production_tpAuth')); if (!tpAuthCookie) { throwCookieNotFoundError('Production_tpAuth', createErrorContext(API_ENDPOINTS.LOGIN_PAGE, 'POST', { username: credentials.username, })); } const authTokenResponse = await getAuthToken(deps.httpClient, submitLoginResponse.cookies || []); if (!authTokenResponse.success) { throwHttpErrorFromResponse(authTokenResponse, 'Get auth token', createErrorContext(API_ENDPOINTS.TOKEN, 'GET')); } if (!authTokenResponse.data) { throwMissingDataError('No auth token data received', createErrorContext(API_ENDPOINTS.TOKEN, 'GET')); } const authTokenData = authTokenResponse.data; const authToken = authTokenData.token; const userResponse = await getUser(deps.httpClient, { accessToken: authToken.access_token, tokenType: authToken.token_type, expiresIn: authToken.expires_in, expires: new Date(authToken.expires), refreshToken: authToken.refresh_token, scope: authToken.scope, }); if (!userResponse.success) { throwHttpErrorFromResponse(userResponse, 'Get user information', createErrorContext(API_ENDPOINTS.USER_PROFILE, 'GET')); } if (!userResponse.data) { throwMissingDataError('No user data received', createErrorContext(API_ENDPOINTS.USER_PROFILE, 'GET')); } const userData = userResponse.data; const user = mapTPUserToUser(userData.user); const token = mapTPTokenToAuthToken(authToken); if (isTokenExpired(token)) { throwTokenExpiredError(createErrorContext(API_ENDPOINTS.TOKEN, 'GET')); } const session = { token, user, }; await deps.sessionStorage.set(session); return session; }; }; const createLogout = (deps) => { return async () => { try { await deps.sessionStorage.clear(); } catch (error) { deps.logger.warn('Failed to clear session storage during logout', { error, }); } }; }; export const createAuthRepository = (deps) => { return { login: createLogin(deps), logout: createLogout(deps), }; };