@mondaycom/apps-cli
Version:
A cli tool to manage apps (and monday-code projects) in monday.com
94 lines (93 loc) • 3.85 kB
JavaScript
import crypto from 'node:crypto';
import https from 'node:https';
import axios, { AxiosError } from 'axios';
import { default as axiosRetry, isIdempotentRequestError, isNetworkError } from 'axios-retry';
import { CONFIG_KEYS } from '../consts/config.js';
import { ACCESS_TOKEN_NOT_FOUND } from '../consts/messages.js';
import { ConfigService } from './config-service.js';
import { getAppsDomain } from './env-service.js';
import { HttpError } from '../types/errors/index.js';
import { wrapInBox } from '../utils/cli-utils.js';
import logger from '../utils/logger.js';
const DEFAULT_TIMEOUT = 10 * 1000;
axiosRetry(axios, {
retries: 5, // number of retries
retryDelay: retryCount => retryCount * 1000,
retryCondition: error => {
const retriableStatusCodes = [500, 502, 503, 504];
const isRetriableStatusCode = error.response && retriableStatusCodes.includes(error.response.status);
return isRetriableStatusCode || isNetworkError(error) || isIdempotentRequestError(error);
},
});
const validateResponseIfError = (response, schemaValidator) => {
if (schemaValidator) {
const parsedResponse = schemaValidator.safeParse(response);
if (parsedResponse.success) {
return parsedResponse.data;
}
const { error } = parsedResponse;
logger.debug(error, 'Invalid response');
throw new Error(`An unknown error occurred. Please contact support.`);
}
return response;
};
const printTraceIdIfPresent = (traceId, statusCode) => {
if (traceId) {
const traceErrorMessage = `ErrorTraceId: ${traceId}`;
const traceIdBox = wrapInBox(traceErrorMessage);
statusCode && statusCode >= 500 ? logger.error(traceIdBox) : logger.debug(traceIdBox);
}
};
const handleErrors = (error) => {
const defaultErrorMessage = `Unexpected error occurred while communicating with the remote server`;
if (error instanceof AxiosError) {
const errorAxiosResponse = error.response?.data;
const statusCode = error.response?.status;
const title = errorAxiosResponse?.title;
const message = errorAxiosResponse?.message || defaultErrorMessage;
const traceId = errorAxiosResponse?.traceId?.toString();
printTraceIdIfPresent(traceId, statusCode);
throw new HttpError(message, title, statusCode);
}
else if (error instanceof Error) {
const message = error.message || defaultErrorMessage;
throw new HttpError(message);
}
else {
throw new HttpError('An unknown error occurred.');
}
};
export async function execute(params, schemaValidator) {
const DEBUG_TAG = 'api_service';
const accessToken = ConfigService.getConfigDataByKey(CONFIG_KEYS.ACCESS_TOKEN);
if (!accessToken) {
logger.error(ACCESS_TOKEN_NOT_FOUND);
throw new Error(ACCESS_TOKEN_NOT_FOUND);
}
const { body: data, query, url, method, timeout, headers } = params;
const headersWithToken = { ...headers, Authorization: accessToken };
const baseURL = getAppsDomain();
try {
const httpsAgent = new https.Agent({
secureOptions: crypto.constants.SSL_OP_LEGACY_SERVER_CONNECT,
rejectUnauthorized: false,
});
const response = await axios.request({
httpsAgent,
method,
baseURL,
url,
data,
headers: headersWithToken,
params: query,
timeout: timeout || DEFAULT_TIMEOUT,
});
logger.debug({ res: response }, DEBUG_TAG);
const result = { ...response.data, statusCode: 200, headers: response.headers };
const validatedResult = validateResponseIfError(result, schemaValidator);
return validatedResult || result;
}
catch (error) {
return handleErrors(error);
}
}