@contentstack/management
Version:
The Content Management API is used to manage the content of your Contentstack account
377 lines (367 loc) • 15.3 kB
JavaScript
;
var _interopRequireDefault3 = require("@babel/runtime/helpers/interopRequireDefault");
var _interopRequireDefault2 = _interopRequireDefault3(require("@babel/runtime/helpers/interopRequireDefault"));
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperty2 = require("@babel/runtime/helpers/defineProperty");
var _defineProperty3 = (0, _interopRequireDefault2["default"])(_defineProperty2);
var _asyncToGenerator2 = require("@babel/runtime/helpers/asyncToGenerator");
var _asyncToGenerator3 = (0, _interopRequireDefault2["default"])(_asyncToGenerator2);
exports.ConcurrencyQueue = ConcurrencyQueue;
var _regenerator = require("@babel/runtime/regenerator");
var _regenerator2 = (0, _interopRequireDefault2["default"])(_regenerator);
var _axios = require("axios");
var _axios2 = (0, _interopRequireDefault2["default"])(_axios);
var _oauthHandler = require("./oauthHandler");
var _oauthHandler2 = (0, _interopRequireDefault2["default"])(_oauthHandler);
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty3["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var defaultConfig = {
maxRequests: 5,
retryLimit: 5,
retryDelay: 300
};
function ConcurrencyQueue(_ref) {
var _this = this;
var axios = _ref.axios,
config = _ref.config;
if (!axios) {
throw Error('Axios instance is not present');
}
if (config) {
if (config.maxRequests && config.maxRequests <= 0) {
throw Error('Concurrency Manager Error: minimum concurrent requests is 1');
} else if (config.retryLimit && config.retryLimit <= 0) {
throw Error('Retry Policy Error: minimum retry limit is 1');
} else if (config.retryDelay && config.retryDelay < 300) {
throw Error('Retry Policy Error: minimum retry delay for requests is 300');
}
}
this.config = Object.assign({}, defaultConfig, config);
this.queue = [];
this.running = [];
this.paused = false;
// Initial shift will check running request,
// and adds request to running queue if max requests are not running
this.initialShift = function () {
if (_this.running.length < _this.config.maxRequests && !_this.paused) {
shift();
}
};
// INTERNAL: Shift the queued item to running queue
var shift = function shift() {
if (_this.queue.length && !_this.paused) {
var queueItem = _this.queue.shift();
queueItem.resolve(queueItem.request);
_this.running.push(queueItem);
}
};
// Append the request at start of queue
this.unshift = function (requestPromise) {
_this.queue.unshift(requestPromise);
};
this.push = function (requestPromise) {
_this.queue.push(requestPromise);
_this.initialShift();
};
this.clear = function () {
var requests = _this.queue.splice(0, _this.queue.length);
requests.forEach(function (element) {
element.request.source.cancel();
});
};
// Detach the interceptors
this.detach = function () {
axios.interceptors.request.eject(_this.interceptors.request);
axios.interceptors.response.eject(_this.interceptors.response);
_this.interceptors = {
request: null,
response: null
};
};
// Request interceptor to queue the request
var requestHandler = function requestHandler(request) {
var _axios$oauth;
if (typeof request.data === 'function') {
request.formdata = request.data;
request.data = transformFormData(request);
}
if (axios !== null && axios !== void 0 && (_axios$oauth = axios.oauth) !== null && _axios$oauth !== void 0 && _axios$oauth.accessToken) {
var isTokenExpired = axios.oauth.tokenExpiryTime && Date.now() > axios.oauth.tokenExpiryTime;
if (isTokenExpired) {
return refreshAccessToken()["catch"](function (error) {
throw new Error('Failed to refresh access token: ' + error.message);
});
}
}
request.retryCount = (request === null || request === void 0 ? void 0 : request.retryCount) || 0;
setAuthorizationHeaders(request);
if (request.cancelToken === undefined) {
var source = _axios2["default"].CancelToken.source();
request.cancelToken = source.token;
request.source = source;
}
if (_this.paused && request.retryCount > 0) {
return new Promise(function (resolve, reject) {
_this.unshift({
request: request,
resolve: resolve,
reject: reject
});
});
} else if (request.retryCount > 0) {
return request;
}
return new Promise(function (resolve, reject) {
request.onComplete = function () {
_this.running.pop({
request: request,
resolve: resolve,
reject: reject
});
};
_this.push({
request: request,
resolve: resolve,
reject: reject
});
});
};
var setAuthorizationHeaders = function setAuthorizationHeaders(request) {
var _axios$oauth2;
if (request.headers.authorization && request.headers.authorization !== undefined) {
if (_this.config.authorization && _this.config.authorization !== undefined) {
request.headers.authorization = _this.config.authorization;
request.authorization = _this.config.authorization;
}
delete request.headers.authtoken;
} else if (request.headers.authtoken && request.headers.authtoken !== undefined && _this.config.authtoken && _this.config.authtoken !== undefined) {
request.headers.authtoken = _this.config.authtoken;
request.authtoken = _this.config.authtoken;
} else if (axios !== null && axios !== void 0 && (_axios$oauth2 = axios.oauth) !== null && _axios$oauth2 !== void 0 && _axios$oauth2.accessToken) {
// If OAuth access token is available in axios instance
request.headers.authorization = "Bearer ".concat(axios.oauth.accessToken);
request.authorization = "Bearer ".concat(axios.oauth.accessToken);
delete request.headers.authtoken;
}
};
// Refresh Access Token
var refreshAccessToken = /*#__PURE__*/function () {
var _ref2 = (0, _asyncToGenerator3["default"])(/*#__PURE__*/_regenerator2["default"].mark(function _callee() {
return _regenerator2["default"].wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
_context.prev = 0;
_context.next = 3;
return new _oauthHandler2["default"](axios).refreshAccessToken();
case 3:
_this.paused = false; // Resume the request queue once the token is refreshed
// Retry the requests that were pending due to token expiration
_this.running.forEach(function (_ref3) {
var request = _ref3.request,
resolve = _ref3.resolve,
reject = _ref3.reject;
// Retry the request
axios(request).then(resolve)["catch"](reject);
});
_this.running = []; // Clear the running queue after retrying requests
_context.next = 13;
break;
case 8:
_context.prev = 8;
_context.t0 = _context["catch"](0);
_this.paused = false; // stop queueing requests on failure
_this.running.forEach(function (_ref4) {
var reject = _ref4.reject;
return reject(_context.t0);
}); // Reject all queued requests
_this.running = []; // Clear the running queue
case 13:
case "end":
return _context.stop();
}
}, _callee, null, [[0, 8]]);
}));
return function refreshAccessToken() {
return _ref2.apply(this, arguments);
};
}();
var _delay = function delay(time) {
var isRefreshToken = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (!_this.paused) {
_this.paused = true;
// Check for current running request.
// Wait for running queue to complete.
// Wait and prosed the Queued request.
if (_this.running.length > 0) {
setTimeout(function () {
_delay(time, isRefreshToken);
}, time);
}
return new Promise(function (resolve) {
return setTimeout(function () {
_this.paused = false;
if (isRefreshToken) {
return refreshToken();
} else {
for (var i = 0; i < _this.config.maxRequests; i++) {
_this.initialShift();
}
}
}, time);
});
}
};
var refreshToken = function refreshToken() {
return config.refreshToken().then(function (token) {
if (token.authorization) {
axios.defaults.headers.authorization = token.authorization;
axios.defaults.authorization = token.authorization;
axios.httpClientParams.authorization = token.authorization;
axios.httpClientParams.headers.authorization = token.authorization;
_this.config.authorization = token.authorization;
} else if (token.authtoken) {
axios.defaults.headers.authtoken = token.authtoken;
axios.defaults.authtoken = token.authtoken;
axios.httpClientParams.authtoken = token.authtoken;
axios.httpClientParams.headers.authtoken = token.authtoken;
_this.config.authtoken = token.authtoken;
}
})["catch"](function (error) {
_this.queue.forEach(function (queueItem) {
queueItem.reject({
errorCode: '401',
errorMessage: error instanceof Error ? error.message : error,
code: 'Unauthorized',
message: 'Unable to refresh token',
name: 'Token Error',
config: queueItem.request,
stack: error instanceof Error ? error.stack : null
});
});
_this.queue = [];
_this.running = [];
})["finally"](function () {
_this.queue.forEach(function (queueItem) {
if (_this.config.authorization) {
queueItem.request.headers.authorization = _this.config.authorization;
queueItem.request.authorization = _this.config.authorization;
}
if (_this.config.authtoken) {
queueItem.request.headers.authtoken = _this.config.authtoken;
queueItem.request.authtoken = _this.config.authtoken;
}
});
for (var i = 0; i < _this.config.maxRequests; i++) {
_this.initialShift();
}
});
};
// Response interceptor used for
var responseHandler = function responseHandler(response) {
response.config.onComplete();
shift();
return response;
};
var responseErrorHandler = function responseErrorHandler(error) {
var networkError = error.config.retryCount;
var retryErrorType = null;
if (!_this.config.retryOnError || networkError > _this.config.retryLimit) {
return Promise.reject(responseHandler(error));
}
// Check rate limit remaining header before retrying
// Error handling
var wait = _this.config.retryDelay;
var response = error.response;
if (!response) {
if (error.code === 'ECONNABORTED') {
error.response = _objectSpread(_objectSpread({}, error.response), {}, {
status: 408,
statusText: "timeout of ".concat(_this.config.timeout, "ms exceeded")
});
response = error.response;
} else {
return Promise.reject(responseHandler(error));
}
} else if (response.status === 401 && _this.config.refreshToken) {
retryErrorType = "Error with status: ".concat(response.status);
networkError++;
if (networkError > _this.config.retryLimit) {
return Promise.reject(responseHandler(error));
}
_this.running.shift();
// Cool down the running requests
_delay(wait, response.status === 401);
error.config.retryCount = networkError;
// deepcode ignore Ssrf: URL is dynamic
return axios(updateRequestConfig(error, retryErrorType, wait));
}
if (_this.config.retryCondition && _this.config.retryCondition(error)) {
retryErrorType = error.response ? "Error with status: ".concat(response.status) : "Error Code:".concat(error.code);
networkError++;
return _this.retry(error, retryErrorType, networkError, wait);
}
return Promise.reject(responseHandler(error));
};
this.retry = function (error, retryErrorType, retryCount, waittime) {
var delaytime = waittime;
if (retryCount > _this.config.retryLimit) {
return Promise.reject(responseHandler(error));
}
if (_this.config.retryDelayOptions) {
if (_this.config.retryDelayOptions.customBackoff) {
delaytime = _this.config.retryDelayOptions.customBackoff(retryCount, error);
if (delaytime && delaytime <= 0) {
return Promise.reject(responseHandler(error));
}
} else if (_this.config.retryDelayOptions.base) {
delaytime = _this.config.retryDelayOptions.base * retryCount;
}
} else {
delaytime = _this.config.retryDelay;
}
error.config.retryCount = retryCount;
return new Promise(function (resolve) {
return setTimeout(function () {
// deepcode ignore Ssrf: URL is dynamic
return resolve(axios(updateRequestConfig(error, retryErrorType, delaytime)));
}, delaytime);
});
};
this.interceptors = {
request: null,
response: null
};
var updateRequestConfig = function updateRequestConfig(error, retryErrorType, wait) {
var requestConfig = error.config;
_this.config.logHandler('warning', "".concat(retryErrorType, " error occurred. Waiting for ").concat(wait, " ms before retrying..."));
if (axios !== undefined && axios.defaults !== undefined) {
if (axios.defaults.agent === requestConfig.agent) {
delete requestConfig.agent;
}
if (axios.defaults.httpAgent === requestConfig.httpAgent) {
delete requestConfig.httpAgent;
}
if (axios.defaults.httpsAgent === requestConfig.httpsAgent) {
delete requestConfig.httpsAgent;
}
}
requestConfig.data = transformFormData(requestConfig);
requestConfig.transformRequest = [function (data) {
return data;
}];
return requestConfig;
};
var transformFormData = function transformFormData(request) {
if (request.formdata) {
var formdata = request.formdata();
request.headers = _objectSpread(_objectSpread({}, request.headers), formdata.getHeaders());
return formdata;
}
return request.data;
};
// Adds interseptors in axios to queue request
this.interceptors.request = axios.interceptors.request.use(requestHandler);
this.interceptors.response = axios.interceptors.response.use(responseHandler, responseErrorHandler);
}