@sap/cli-core
Version:
Command-Line Interface (CLI) Core Module
83 lines (82 loc) • 3.34 kB
JavaScript
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);
};