"use strict";

var _Object$keys2 = require("@babel/runtime-corejs3/core-js-stable/object/keys");
var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols");
var _filterInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/filter");
var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor");
var _forEachInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/for-each");
var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors");
var _Object$defineProperties = require("@babel/runtime-corejs3/core-js-stable/object/define-properties");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
_Object$defineProperty(exports, "__esModule", {
  value: true
});
exports.ResponseError = ResponseError;
exports.TIMEOUT_ERROR = void 0;
exports.default = baseRequest;
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs3/regenerator"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
var _typeof2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/typeof"));
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/objectWithoutProperties"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/asyncToGenerator"));
var _setTimeout2 = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/set-timeout"));
var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array"));
var _keys = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/object/keys"));
var _stringify = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/json/stringify"));
var _concat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/concat"));
var _abortController = _interopRequireDefault(require("abort-controller"));
var _es6Promise = require("es6-promise");
var _fetchPonyfill = _interopRequireDefault(require("fetch-ponyfill"));
var _sprintfJs = require("sprintf-js");
var _format_text = _interopRequireDefault(require("./format_text"));
var _stringify_as_query_param = _interopRequireDefault(require("./stringify_as_query_param"));
var _excluded = ["jsonBody", "query", "urlTemplateSpec"];
function ownKeys(object, enumerableOnly) { var keys = _Object$keys2(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context3, _context4; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty(_context3 = ownKeys(Object(source), !0)).call(_context3, function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context4 = ownKeys(Object(source))).call(_context4, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } return target; }
var fetch = (0, _fetchPonyfill.default)({
  Promise: _es6Promise.Promise
});
var TIMEOUT_ERROR = 'TimeoutError';
exports.TIMEOUT_ERROR = TIMEOUT_ERROR;
function ResponseError(message, status, requestURI) {
  this.name = 'ResponseError';
  this.message = message;
  this.status = status;
  this.requestURI = requestURI;
  this.stack = new Error().stack;
}
ResponseError.prototype = new Error();

/**
 * Timeout function following https://github.com/github/fetch/issues/175#issuecomment-284787564
 * @private
 * @param {integer} ms timeout
 * @param {Promise} promise Fetch promise
 * @param {AbortController} controller AbortController instance bound to fetch
 * @return {Promise} TimeoutError if the time was consumed, otherwise the Promise will be resolved
 */
function timeout(ms, promise, controller) {
  return new _es6Promise.Promise(function (resolve, reject) {
    var nodeTimeout = (0, _setTimeout2.default)(function () {
      controller.abort();
      reject(new Error(TIMEOUT_ERROR));
    }, ms);
    promise.then(function (res) {
      clearTimeout(nodeTimeout);
      resolve(res);
    }).catch(function (err) {
      clearTimeout(nodeTimeout);
      reject(err);
    });
  });
}

/**
 * @private
 * @param {Response} res Source object
 * @return {Promise} Promise that will resolve with the response if its status was 2xx;
 *                          otherwise rejects with the ResponseError
 */
function handleResponse(_x) {
  return _handleResponse.apply(this, arguments);
}
/**
 * @private
 * imported from https://github.com/bigchaindb/js-utility-belt/
 *
 * Global fetch wrapper that adds some basic error handling and ease of use enhancements.
 * Considers any non-2xx response as an error.
 *
 * For more information on fetch, see https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch.
 *
 * Expects fetch to already be available (either in a ES6 environment, bundled through webpack, or
 * injected through a polyfill).
 *
 * @param  {string}  url    Url to request. Can be specified as a sprintf format string (see
 *                          https://github.com/alexei/sprintf.js) that will be resolved using
 *                          `config.urlTemplateSpec`.
 * @param  {Object}  config Additional configuration, mostly passed to fetch as its 'init' config
 *                          (see https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch#Parameters).
 * @param  {*}             config.jsonBody        Json payload to the request. Will automatically be
 *                                                JSON.stringify()-ed and override `config.body`.
 * @param  {string|Object} config.query           Query parameter to append to the end of the url.
 *                                                If specified as an object, keys will be
 *                                                decamelized into snake case first.
 * @param  {*[]|Object}     config.urlTemplateSpec Format spec to use to expand the url (see sprintf).
 * @param  {*}              config.*               All other options are passed through to fetch.
 * @param  {integer}        requestTimeout         Timeout for a single request
 *
 * @return {Promise}        If requestTimeout the timeout function will be called. Otherwise resolve the
 *                          Promise with the handleResponse function
 */
function _handleResponse() {
  _handleResponse = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(res) {
    var _res$headers;
    var contentType, isJson, body, _context;
    return _regenerator.default.wrap(function _callee$(_context2) {
      while (1) switch (_context2.prev = _context2.next) {
        case 0:
          // If status is not a 2xx (based on Response.ok), assume it's an error
          // See https://developer.mozilla.org/en-US/docs/Web/API/GlobalFetch/fetch
          contentType = (_res$headers = res.headers) === null || _res$headers === void 0 ? void 0 : _res$headers.get('content-type');
          isJson = contentType === 'application/json';
          if (!isJson) {
            _context2.next = 8;
            break;
          }
          _context2.next = 5;
          return res.json();
        case 5:
          _context2.t0 = _context2.sent;
          _context2.next = 9;
          break;
        case 8:
          _context2.t0 = undefined;
        case 9:
          body = _context2.t0;
          if (res && res.ok) {
            _context2.next = 12;
            break;
          }
          throw new ResponseError((body === null || body === void 0 ? void 0 : body.message) || 'HTTP Error: Requested page not reachable', (0, _concat.default)(_context = "".concat(res.status, " ")).call(_context, res.statusText), res.url);
        case 12:
          return _context2.abrupt("return", body || {
            ok: true
          });
        case 13:
        case "end":
          return _context2.stop();
      }
    }, _callee);
  }));
  return _handleResponse.apply(this, arguments);
}
function baseRequest(url) {
  var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  var requestTimeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
  var jsonBody = _ref.jsonBody,
    query = _ref.query,
    urlTemplateSpec = _ref.urlTemplateSpec,
    fetchConfig = (0, _objectWithoutProperties2.default)(_ref, _excluded);
  var expandedUrl = url;
  if (urlTemplateSpec != null) {
    if ((0, _isArray.default)(urlTemplateSpec) && urlTemplateSpec.length) {
      // Use vsprintf for the array call signature
      expandedUrl = (0, _sprintfJs.vsprintf)(url, urlTemplateSpec);
    } else if (urlTemplateSpec && (0, _typeof2.default)(urlTemplateSpec) === 'object' && (0, _keys.default)(urlTemplateSpec).length) {
      expandedUrl = (0, _format_text.default)(url, urlTemplateSpec);
    } else if (process.env.NODE_ENV !== 'production') {
      // eslint-disable-next-line no-console
      console.warn('Supplied urlTemplateSpec was not an array or object. Ignoring...');
    }
  }
  if (query != null) {
    if (typeof query === 'string') {
      expandedUrl += query;
    } else if (query && (0, _typeof2.default)(query) === 'object') {
      expandedUrl += (0, _stringify_as_query_param.default)(query);
    } else if (process.env.NODE_ENV !== 'production') {
      // eslint-disable-next-line no-console
      console.warn('Supplied query was not a string or object. Ignoring...');
    }
  }
  if (jsonBody != null) {
    fetchConfig.body = (0, _stringify.default)(jsonBody);
  }
  if (requestTimeout) {
    var controller = new _abortController.default();
    var signal = controller.signal;
    return timeout(requestTimeout, fetch.fetch(expandedUrl, _objectSpread(_objectSpread({}, fetchConfig), {}, {
      signal: signal
    })), controller).then(handleResponse);
  }
  return fetch.fetch(expandedUrl, fetchConfig).then(handleResponse);
}
//# sourceMappingURL=baseRequest.js.map