UNPKG

@sap/cli-core

Version:

Command-Line Interface (CLI) Core Module

83 lines (82 loc) 3.34 kB
import { get as getConfig } from "../../../config/index.js"; import { X_CSRF_TOKEN } from "../../../constants.js"; import { get } from "../../../logger/index.js"; import { fetch } from "../../../utils/http/index.js"; import { refreshToken } from "../authentication/oauth/tokenProvider/utils.js"; import { buildHttpConfig, checkConfiguration, handleResponse, handleResponseData, } from "./utils.js"; const getLogger = () => get("commands.handler.fetch"); const hasResponse = (err) => { return !!err.response; }; const removeCsrfTokenFromConfig = () => { const config = getConfig(); delete config[X_CSRF_TOKEN]; }; // developer.mozilla.org/en-US/docs/Web/HTTP/Redirections const REDIRECT_STATUS_CODES = [301, 302, 303, 307, 308]; const REDIRECT_WITHOUT_CHANGE = [307, 308]; const fetchData = async (method, path, parameterMappings, responsePostProcessor) => { const config = getConfig(); checkConfiguration(config); const conf = await buildHttpConfig(method, path, parameterMappings); const response = await fetch(conf); removeCsrfTokenFromConfig(); await handleResponse(response.data, response.headers); if (responsePostProcessor) { await responsePostProcessor(response); } }; const handle401 = async (method, path, parameterMappings) => { const { debug, error } = getLogger(); debug("response status is 401, trying to refresh access_token"); try { await refreshToken(true); await fetchData(method, path, parameterMappings); debug("refreshing token and fetching data succeeded"); } catch (errRefresh) { error("refreshing token and fetching data again failed", errRefresh); throw errRefresh; } }; const handleRedirect = async (error, method, redirect) => { if (!error.response.headers.location) { throw new Error("location header is not present for redirect"); } let newMethod = method; if (!REDIRECT_WITHOUT_CHANGE.includes(error.response.status)) { newMethod = "GET"; } await redirect(newMethod, error.response.headers.location); }; const handleError = async (error, method, redirect, path, parameterMappings) => { const { error: logError } = getLogger(); logError("failed to fetch data", error); if (error.response?.data && getConfig().verbose) { await handleResponseData(error.response.data); } if (error.response?.status === 401) { await handle401(method, path, parameterMappings); } else if (hasResponse(error) && REDIRECT_STATUS_CODES.includes(error.response.status)) { await handleRedirect(error, method, redirect); } else { throw error; } }; const runRequest = (method, path, parameterMappings, responsePostProcessor) => async () => { try { await fetchData(method, path, parameterMappings, responsePostProcessor); } catch (errFetch) { const redirect = (newMethod, location) => runRequest(newMethod, location, parameterMappings, responsePostProcessor)(); await handleError(errFetch, method, redirect, path, parameterMappings); } }; /* jscpd:ignore-start */ export const create = (method, path, parameterMappings, responsePostProcessor) => { /* jscpd:ignore-end */ return async () => runRequest(method, path, parameterMappings, responsePostProcessor); };