steadybit
Version:
Command-line interface to interact with the Steadybit API
152 lines • 6 kB
JavaScript
;
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2022 Steadybit GmbH
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.options = void 0;
exports.enableRequestLogging = enableRequestLogging;
exports.executeApiCall = executeApiCall;
const node_fetch_1 = __importDefault(require("node-fetch"));
const common_1 = require("./common");
/*
* This is required because we are supporting Node.js v14
*/
const requirePlatformAccess_1 = require("../config/requirePlatformAccess");
const http_1 = __importDefault(require("http"));
const https_1 = __importDefault(require("https"));
const TOO_MANY_REQUESTS = 429;
exports.options = {
maxRetries: 2,
defaultWaitTime: 1000,
};
const httpAgentOptions = {
keepAlive: true,
keepAliveMsecs: 60000,
timeout: 60000,
maxSockets: 64,
};
const httpAgent = new http_1.default.Agent(httpAgentOptions);
const httpsAgent = new https_1.default.Agent(httpAgentOptions);
function enableRequestLogging() {
process.env.REQUEST_LOGGING_ENABLED = 'true';
}
function doFetch(url, method, headers, body, controller, redirect) {
return __awaiter(this, void 0, void 0, function* () {
if (process.env.REQUEST_LOGGING_ENABLED === 'true') {
console.log(`> HTTP ${method} ${url}`);
for (const [key, value] of Object.entries(headers)) {
console.log(`> ${key}: ${value}`);
}
console.log(`> `);
if (body) {
console.log(body);
}
console.log('');
}
const response = yield (0, node_fetch_1.default)(url, {
method,
headers,
body,
signal: controller.signal,
agent: getHttpAgent,
redirect,
});
if (process.env.REQUEST_LOGGING_ENABLED === 'true') {
console.log(`< HTTP ${response.status} ${response.statusText}`);
for (const [key, value] of response.headers) {
console.log(`< ${key}: ${value}`);
}
console.log(`< `);
try {
const text = yield response.clone().text();
if (text) {
console.log(text);
}
}
catch (_a) {
// ignore
}
console.log('');
}
return response;
});
}
function executeApiCall(_a) {
return __awaiter(this, arguments, void 0, function* ({ method, path, queryParameters, body, timeout = 30000, expect2xx = true, redirect = 'error', fullyQualifiedUrl = false, }) {
yield (0, requirePlatformAccess_1.ensurePlatformAccessConfigurationIsAvailable)();
const url = fullyQualifiedUrl ? path : yield (0, common_1.toUrl)(path, queryParameters);
const headers = yield (0, common_1.getHeaders)();
const controller = new AbortController();
const response = yield doWithRetry(() => __awaiter(this, void 0, void 0, function* () {
var _a;
const timeoutHandle = setTimeout(() => controller.abort(), timeout);
try {
return yield doFetch(url, method, headers, body ? JSON.stringify(body) : undefined, controller, redirect);
}
catch (e) {
throw new Error(`Failed to call Steadybit API at ${method} ${url}: ${(_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : 'Unknown Cause'}`,
// @ts-expect-error TypeScript doesn't know about error causes yet
{ cause: e });
}
finally {
clearTimeout(timeoutHandle);
}
}));
if (expect2xx && !response.ok) {
let body = '';
try {
body = yield response.text();
}
catch (_b) {
// ignore
}
const error = new Error(`Steadybit API at ${method} ${url} responded with unexpected status code: ${response.status} - ${body !== null && body !== void 0 ? body : '<no body>'}`);
error.response = response;
throw error;
}
return response;
});
}
function doWithRetry(fn) {
return __awaiter(this, void 0, void 0, function* () {
let response;
let retry = 0;
do {
response = yield fn();
if (response.status !== TOO_MANY_REQUESTS) {
break;
}
const resetHeader = response.headers.get('RateLimit-Reset') || response.headers.get('Retry-After');
const retryInSeconds = (resetHeader && Number.parseInt(resetHeader) * 1000) || exports.options.defaultWaitTime;
yield sleep(retryInSeconds);
} while (retry++ <= exports.options.maxRetries);
return response;
});
}
function sleep(millis) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, millis);
});
}
function getHttpAgent(parsedUrl) {
if (parsedUrl.protocol == 'http:') {
return httpAgent;
}
else {
return httpsAgent;
}
}
//# sourceMappingURL=http.js.map