UNPKG

trainingpeaks-sdk

Version:
262 lines (261 loc) 11.1 kB
import { ValidationError } from './domain/errors/index.js'; const HARDCODED_DEFAULTS = { urls: { baseUrl: 'https://www.trainingpeaks.com', apiBaseUrl: 'https://tpapi.trainingpeaks.com', loginUrl: 'https://home.trainingpeaks.com/login', appUrl: 'https://app.trainingpeaks.com', tokenUrl: 'https://tpapi.trainingpeaks.com/users/v3/token', userInfoUrl: 'https://tpapi.trainingpeaks.com/users/v3/user', }, auth: { cookieName: 'Production_tpAuth', }, timeouts: { default: 30000, webAuth: 30000, apiAuth: 30000, elementWait: 5000, pageLoad: 2000, errorDetection: 15000, testExecution: 60000, }, tokens: { refreshWindow: 300000, validationWindow: 60000, defaultExpiration: 82800000, }, browser: { headless: true, executablePath: '', launchTimeout: 30000, pageWaitTimeout: 2000, }, debug: { enabled: false, level: 'info', logAuth: false, logNetwork: false, logBrowser: false, }, requests: { defaultHeaders: { 'User-Agent': 'TrainingPeaks-SDK/1.0.0', Accept: 'application/json', 'Content-Type': 'application/json', }, retryAttempts: 3, retryDelay: 1000, }, }; function getEnvironmentConfig() { return { urls: { baseUrl: process.env.TRAININGPEAKS_BASE_URL || undefined, apiBaseUrl: process.env.TRAININGPEAKS_API_BASE_URL || undefined, loginUrl: process.env.TRAININGPEAKS_LOGIN_URL || undefined, appUrl: process.env.TRAININGPEAKS_APP_URL || undefined, tokenUrl: process.env.TRAININGPEAKS_TOKEN_URL || undefined, userInfoUrl: process.env.TRAININGPEAKS_USER_INFO_URL || undefined, }, auth: { cookieName: process.env.TRAININGPEAKS_AUTH_COOKIE_NAME || undefined, }, timeouts: { default: process.env.TRAININGPEAKS_TIMEOUT ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_TIMEOUT, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, webAuth: process.env.TRAININGPEAKS_WEB_AUTH_TIMEOUT ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_WEB_AUTH_TIMEOUT, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, apiAuth: process.env.TRAININGPEAKS_API_AUTH_TIMEOUT ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_API_AUTH_TIMEOUT, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, elementWait: process.env.TRAININGPEAKS_ELEMENT_WAIT_TIMEOUT ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_ELEMENT_WAIT_TIMEOUT, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, pageLoad: process.env.TRAININGPEAKS_PAGE_LOAD_TIMEOUT ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_PAGE_LOAD_TIMEOUT, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, errorDetection: process.env.TRAININGPEAKS_ERROR_DETECTION_TIMEOUT ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_ERROR_DETECTION_TIMEOUT, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, testExecution: process.env.TRAININGPEAKS_TEST_EXECUTION_TIMEOUT ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_TEST_EXECUTION_TIMEOUT, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, }, tokens: { refreshWindow: process.env.TRAININGPEAKS_TOKEN_REFRESH_WINDOW ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_TOKEN_REFRESH_WINDOW, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, validationWindow: process.env.TRAININGPEAKS_TOKEN_VALIDATION_WINDOW ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_TOKEN_VALIDATION_WINDOW, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, defaultExpiration: process.env.TRAININGPEAKS_TOKEN_DEFAULT_EXPIRATION ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_TOKEN_DEFAULT_EXPIRATION, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, }, browser: { headless: process.env.TRAININGPEAKS_BROWSER_HEADLESS !== undefined ? process.env.TRAININGPEAKS_BROWSER_HEADLESS !== 'false' : undefined, executablePath: process.env.TRAININGPEAKS_BROWSER_EXECUTABLE_PATH || undefined, launchTimeout: process.env.TRAININGPEAKS_BROWSER_LAUNCH_TIMEOUT ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_BROWSER_LAUNCH_TIMEOUT, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, pageWaitTimeout: process.env.TRAININGPEAKS_BROWSER_PAGE_WAIT_TIMEOUT ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_BROWSER_PAGE_WAIT_TIMEOUT, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, }, debug: { enabled: process.env.TRAININGPEAKS_DEBUG !== undefined ? process.env.TRAININGPEAKS_DEBUG === 'true' : undefined, logAuth: process.env.TRAININGPEAKS_DEBUG_AUTH !== undefined ? process.env.TRAININGPEAKS_DEBUG_AUTH === 'true' : undefined, logNetwork: process.env.TRAININGPEAKS_DEBUG_NETWORK !== undefined ? process.env.TRAININGPEAKS_DEBUG_NETWORK === 'true' : undefined, logBrowser: process.env.TRAININGPEAKS_DEBUG_BROWSER !== undefined ? process.env.TRAININGPEAKS_DEBUG_BROWSER === 'true' : undefined, }, requests: { defaultHeaders: process.env.TRAININGPEAKS_DEFAULT_HEADERS ? JSON.parse(process.env.TRAININGPEAKS_DEFAULT_HEADERS) : undefined, retryAttempts: process.env.TRAININGPEAKS_RETRY_ATTEMPTS ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_RETRY_ATTEMPTS, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, retryDelay: process.env.TRAININGPEAKS_RETRY_DELAY ? (() => { const parsed = parseInt(process.env.TRAININGPEAKS_RETRY_DELAY, 10); return isNaN(parsed) ? undefined : parsed; })() : undefined, }, }; } function deepMergeConfig(base, overrides) { const result = { ...base }; if (overrides.urls) { result.urls = { ...result.urls, ...overrides.urls }; } if (overrides.timeouts) { result.timeouts = { ...result.timeouts, ...overrides.timeouts }; } if (overrides.tokens) { result.tokens = { ...result.tokens, ...overrides.tokens }; } if (overrides.browser) { result.browser = { ...result.browser, ...overrides.browser }; } if (overrides.debug) { result.debug = { ...result.debug, ...overrides.debug }; } if (overrides.requests) { result.requests = { ...result.requests, ...overrides.requests }; } return result; } export function mergeWithDefaultConfig(userConfig = {}) { const envConfig = getEnvironmentConfig(); const config = { ...HARDCODED_DEFAULTS }; if (envConfig.urls) { const filteredUrls = Object.fromEntries(Object.entries(envConfig.urls).filter(([, value]) => value !== undefined)); config.urls = { ...config.urls, ...filteredUrls }; } if (envConfig.auth) { const filteredAuth = Object.fromEntries(Object.entries(envConfig.auth).filter(([, value]) => value !== undefined)); config.auth = { ...config.auth, ...filteredAuth }; } if (envConfig.timeouts) { const filteredTimeouts = Object.fromEntries(Object.entries(envConfig.timeouts).filter(([, value]) => value !== undefined)); config.timeouts = { ...config.timeouts, ...filteredTimeouts }; } if (envConfig.tokens) { const filteredTokens = Object.fromEntries(Object.entries(envConfig.tokens).filter(([, value]) => value !== undefined)); config.tokens = { ...config.tokens, ...filteredTokens }; } if (envConfig.browser) { const filteredBrowser = Object.fromEntries(Object.entries(envConfig.browser).filter(([, value]) => value !== undefined)); config.browser = { ...config.browser, ...filteredBrowser }; } if (envConfig.debug) { const filteredDebug = Object.fromEntries(Object.entries(envConfig.debug).filter(([, value]) => value !== undefined)); config.debug = { ...config.debug, ...filteredDebug }; } if (envConfig.requests) { const filteredRequests = Object.fromEntries(Object.entries(envConfig.requests).filter(([, value]) => value !== undefined)); config.requests = { ...config.requests, ...filteredRequests }; } return deepMergeConfig(config, userConfig); } export function validateConfig(config) { Object.entries(config.urls).forEach(([key, url]) => { if (!url || typeof url !== 'string') { throw new ValidationError(`Invalid URL configuration for ${key}: ${url}`); } try { new URL(url); } catch { throw new ValidationError(`Invalid URL format for ${key}: ${url}`); } }); Object.entries(config.timeouts).forEach(([key, timeout]) => { if (typeof timeout !== 'number' || timeout < 0) { throw new ValidationError(`Invalid timeout configuration for ${key}: ${timeout}`); } }); Object.entries(config.tokens).forEach(([key, value]) => { if (typeof value !== 'number' || value < 0) { throw new ValidationError(`Invalid token configuration for ${key}: ${value}`); } }); } export function getSDKConfig(userConfig = {}) { const config = mergeWithDefaultConfig(userConfig); validateConfig(config); return config; }