"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _path() {
  const data = _interopRequireDefault(require("path"));

  _path = function () {
    return data;
  };

  return data;
}

function _axios() {
  const data = _interopRequireDefault(require("axios"));

  _axios = function () {
    return data;
  };

  return data;
}

function _concatStream() {
  const data = _interopRequireDefault(require("concat-stream"));

  _concatStream = function () {
    return data;
  };

  return data;
}

function _es6Error() {
  const data = _interopRequireDefault(require("es6-error"));

  _es6Error = function () {
    return data;
  };

  return data;
}

function _fsExtra() {
  const data = _interopRequireDefault(require("fs-extra"));

  _fsExtra = function () {
    return data;
  };

  return data;
}

function _isString() {
  const data = _interopRequireDefault(require("lodash/isString"));

  _isString = function () {
    return data;
  };

  return data;
}

function _FsCache() {
  const data = require("./tools/FsCache");

  _FsCache = function () {
    return data;
  };

  return data;
}

function _Config() {
  const data = _interopRequireDefault(require("./Config"));

  _Config = function () {
    return data;
  };

  return data;
}

function Extract() {
  const data = _interopRequireWildcard(require("./Extract"));

  Extract = function () {
    return data;
  };

  return data;
}

function Session() {
  const data = _interopRequireWildcard(require("./Session"));

  Session = function () {
    return data;
  };

  return data;
}

function _User() {
  const data = _interopRequireDefault(require("./User"));

  _User = function () {
    return data;
  };

  return data;
}

function _UserSettings() {
  const data = _interopRequireDefault(require("./UserSettings"));

  _UserSettings = function () {
    return data;
  };

  return data;
}

function _XDLError() {
  const data = _interopRequireDefault(require("./XDLError"));

  _XDLError = function () {
    return data;
  };

  return data;
}

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

const MAX_CONTENT_LENGTH = 100
/* MB */
* 1024 * 1024;
const TIMER_DURATION = 30000;
const TIMEOUT = 3600000;
let exponentClient = 'xdl';

class ApiError extends _es6Error().default {
  constructor(code, message) {
    super(message);

    _defineProperty(this, "code", void 0);

    _defineProperty(this, "_isApiError", true);

    _defineProperty(this, "serverError", void 0);

    this.code = code;
  }

} // These aren't constants because some commands switch between staging and prod


function _rootBaseUrl() {
  return `${_Config().default.api.scheme}://${_Config().default.api.host}`;
}

function _apiBaseUrl() {
  let rootBaseUrl = _rootBaseUrl();

  if (_Config().default.api.port) {
    rootBaseUrl += ':' + _Config().default.api.port;
  }

  return rootBaseUrl + '/--/api';
}

async function _callMethodAsync(url, method = 'get', requestBody, requestOptions, returnEntireResponse = false) {
  const clientId = await Session().clientIdAsync();
  const session = await _User().default.getSessionAsync();
  const skipValidationToken = process.env['EXPO_SKIP_MANIFEST_VALIDATION_TOKEN'];
  let headers = {
    'Exp-ClientId': clientId,
    'Exponent-Client': exponentClient
  };

  if (skipValidationToken) {
    headers['Exp-Skip-Manifest-Validation-Token'] = skipValidationToken;
  }

  if (session) {
    headers['Expo-Session'] = session.sessionSecret;
  }

  let options = {
    url,
    method,
    headers,
    maxContentLength: MAX_CONTENT_LENGTH
  };

  if (requestBody) {
    options = { ...options,
      data: requestBody
    };
  }

  if (requestOptions) {
    if (requestOptions.formData) {
      let convertedFormData = await _convertFormDataToBuffer(requestOptions.formData);
      let {
        data
      } = convertedFormData;
      options.headers = { ...options.headers,
        ...requestOptions.formData.getHeaders()
      };
      options = { ...options,
        data
      };
    } else {
      options = { ...options,
        ...requestOptions
      };
    }
  }

  let response = await _axios().default.request(options);

  if (!response) {
    throw new Error('Unexpected error: Request failed.');
  }

  let responseBody = response.data;
  var responseObj;

  if ((0, _isString().default)(responseBody)) {
    try {
      responseObj = JSON.parse(responseBody);
    } catch (e) {
      throw new (_XDLError().default)('INVALID_JSON', 'Invalid JSON returned from API: ' + e + '. Response body: ' + responseBody);
    }
  } else {
    responseObj = responseBody;
  }

  if (responseObj.err) {
    let err = new ApiError(responseObj.code || 'API_ERROR', 'API Response Error: ' + responseObj.err);
    err.serverError = responseObj.err;
    throw err;
  } else {
    return returnEntireResponse ? response : responseObj;
  }
}

async function _convertFormDataToBuffer(formData) {
  return new Promise(resolve => {
    formData.pipe((0, _concatStream().default)({
      encoding: 'buffer'
    }, data => resolve({
      data
    })));
  });
}

async function _downloadAsync(url, outputPath, progressFunction, retryFunction) {
  let promptShown = false;
  let currentProgress = 0;

  let {
    cancel,
    token
  } = _axios().default.CancelToken.source();

  let warningTimer = setTimeout(() => {
    if (retryFunction) {
      retryFunction(cancel);
    }

    promptShown = true;
  }, TIMER_DURATION);
  const tmpPath = `${outputPath}.download`;
  const config = {
    timeout: TIMEOUT,
    responseType: 'stream',
    cancelToken: token
  };
  let response = await (0, _axios().default)(url, config);
  await new Promise(resolve => {
    let totalDownloadSize = response.data.headers['content-length'];
    let downloadProgress = 0;
    response.data.on('data', chunk => {
      downloadProgress += chunk.length;
      const roundedProgress = Math.floor(downloadProgress / totalDownloadSize * 100);

      if (currentProgress !== roundedProgress) {
        currentProgress = roundedProgress;
        clearTimeout(warningTimer);

        if (!promptShown) {
          warningTimer = setTimeout(() => {
            if (retryFunction) {
              retryFunction(cancel);
            }

            promptShown = true;
          }, TIMER_DURATION);
        }

        if (progressFunction) {
          progressFunction(roundedProgress);
        }
      }
    }).on('end', () => {
      clearTimeout(warningTimer);

      if (progressFunction && currentProgress !== 100) {
        progressFunction(100);
      }

      resolve();
    }).pipe(_fsExtra().default.createWriteStream(tmpPath));
  });
  await _fsExtra().default.rename(tmpPath, outputPath);
}

class ApiClient {
  static setClientName(name) {
    exponentClient = name;
  }

  static async callMethodAsync(methodName, args, method, requestBody, requestOptions = {}, returnEntireResponse = false) {
    let url = _apiBaseUrl() + '/' + encodeURIComponent(methodName) + '/' + encodeURIComponent(JSON.stringify(args));
    return _callMethodAsync(url, method, requestBody, requestOptions, returnEntireResponse);
  }

  static async callPathAsync(path, method, requestBody, requestOptions = {}) {
    let url = _rootBaseUrl() + path;
    return _callMethodAsync(url, method, requestBody, requestOptions);
  }

  static async xdlSchemaAsync(sdkVersion) {
    if (!ApiClient._schemaCaches.hasOwnProperty(sdkVersion)) {
      ApiClient._schemaCaches[sdkVersion] = new (_FsCache().Cacher)(async () => {
        return await ApiClient.callPathAsync(`/--/xdl-schema/${sdkVersion}`);
      }, `schema-${sdkVersion}.json`, 0, _path().default.join(__dirname, `../caches/schema-${sdkVersion}.json`));
    }

    return await ApiClient._schemaCaches[sdkVersion].getAsync();
  }

  static async downloadAsync(url, outputPath, {
    extract = false
  } = {}, progressFunction, retryFunction) {
    if (extract) {
      let dotExpoHomeDirectory = _UserSettings().default.dotExpoHomeDirectory();

      let tmpPath = _path().default.join(dotExpoHomeDirectory, 'tmp-download-file');

      await _downloadAsync(url, tmpPath);
      await Extract().extractAsync(tmpPath, outputPath);

      _fsExtra().default.removeSync(tmpPath);
    } else {
      await _downloadAsync(url, outputPath, progressFunction, retryFunction);
    }
  }

}

exports.default = ApiClient;

_defineProperty(ApiClient, "host", _Config().default.api.host);

_defineProperty(ApiClient, "port", _Config().default.api.port || 80);

_defineProperty(ApiClient, "_schemaCaches", {});
//# sourceMappingURL=__sourcemaps__/Api.js.map