'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var oauthAuthorizationUrl = require('@octokit/oauth-authorization-url');
var request = require('@octokit/request');
var requestError = require('@octokit/request-error');
var btoa = _interopDefault(require('btoa-lite'));

const VERSION = "1.2.2";

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;
}

function ownKeys(object, enumerableOnly) {
  var keys = Object.keys(object);

  if (Object.getOwnPropertySymbols) {
    var symbols = Object.getOwnPropertySymbols(object);
    if (enumerableOnly) symbols = symbols.filter(function (sym) {
      return Object.getOwnPropertyDescriptor(object, sym).enumerable;
    });
    keys.push.apply(keys, symbols);
  }

  return keys;
}

function _objectSpread2(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i] != null ? arguments[i] : {};

    if (i % 2) {
      ownKeys(Object(source), true).forEach(function (key) {
        _defineProperty(target, key, source[key]);
      });
    } else if (Object.getOwnPropertyDescriptors) {
      Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
    } else {
      ownKeys(Object(source)).forEach(function (key) {
        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
      });
    }
  }

  return target;
}

function _objectWithoutPropertiesLoose(source, excluded) {
  if (source == null) return {};
  var target = {};
  var sourceKeys = Object.keys(source);
  var key, i;

  for (i = 0; i < sourceKeys.length; i++) {
    key = sourceKeys[i];
    if (excluded.indexOf(key) >= 0) continue;
    target[key] = source[key];
  }

  return target;
}

function _objectWithoutProperties(source, excluded) {
  if (source == null) return {};

  var target = _objectWithoutPropertiesLoose(source, excluded);

  var key, i;

  if (Object.getOwnPropertySymbols) {
    var sourceSymbolKeys = Object.getOwnPropertySymbols(source);

    for (i = 0; i < sourceSymbolKeys.length; i++) {
      key = sourceSymbolKeys[i];
      if (excluded.indexOf(key) >= 0) continue;
      if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
      target[key] = source[key];
    }
  }

  return target;
}

function requestToOAuthBaseUrl(request) {
  const endpointDefaults = request.endpoint.DEFAULTS;
  return /^https:\/\/(api\.)?github\.com$/.test(endpointDefaults.baseUrl) ? "https://github.com" : endpointDefaults.baseUrl.replace("/api/v3", "");
}
async function oauthRequest(request, route, parameters) {
  const withOAuthParameters = _objectSpread2({
    baseUrl: requestToOAuthBaseUrl(request),
    headers: {
      accept: "application/json"
    }
  }, parameters);

  const response = await request(route, withOAuthParameters);

  if ("error" in response.data) {
    const error = new requestError.RequestError(`${response.data.error_description} (${response.data.error}, ${response.data.error_url})`, 400, {
      request: request.endpoint.merge(route, withOAuthParameters),
      headers: response.headers
    }); // @ts-ignore add custom response property until https://github.com/octokit/request-error.js/issues/169 is resolved

    error.response = response;
    throw error;
  }

  return response;
}

function getWebFlowAuthorizationUrl(_ref) {
  let {
    request: request$1 = request.request
  } = _ref,
      options = _objectWithoutProperties(_ref, ["request"]);

  const baseUrl = requestToOAuthBaseUrl(request$1); // @ts-expect-error TypeScript wants `clientType` to be set explicitly ¯\_(ツ)_/¯

  return oauthAuthorizationUrl.oauthAuthorizationUrl(_objectSpread2(_objectSpread2({}, options), {}, {
    baseUrl
  }));
}

async function exchangeWebFlowCode(options) {
  const request$1 = options.request ||
  /* istanbul ignore next: we always pass a custom request in tests */
  request.request;
  const response = await oauthRequest(request$1, "POST /login/oauth/access_token", {
    client_id: options.clientId,
    client_secret: options.clientSecret,
    code: options.code,
    redirect_uri: options.redirectUrl,
    state: options.state
  });
  const authentication = {
    clientType: options.clientType,
    clientId: options.clientId,
    clientSecret: options.clientSecret,
    token: response.data.access_token,
    scopes: response.data.scope.split(/\s+/).filter(Boolean)
  };

  if (options.clientType === "github-app") {
    if ("refresh_token" in response.data) {
      const apiTimeInMs = new Date(response.headers.date).getTime();
      authentication.refreshToken = response.data.refresh_token, authentication.expiresAt = toTimestamp(apiTimeInMs, response.data.expires_in), authentication.refreshTokenExpiresAt = toTimestamp(apiTimeInMs, response.data.refresh_token_expires_in);
    }

    delete authentication.scopes;
  }

  return _objectSpread2(_objectSpread2({}, response), {}, {
    authentication
  });
}

function toTimestamp(apiTimeInMs, expirationInSeconds) {
  return new Date(apiTimeInMs + expirationInSeconds * 1000).toISOString();
}

async function createDeviceCode(options) {
  const request$1 = options.request ||
  /* istanbul ignore next: we always pass a custom request in tests */
  request.request;
  const parameters = {
    client_id: options.clientId
  };

  if ("scopes" in options && Array.isArray(options.scopes)) {
    parameters.scope = options.scopes.join(" ");
  }

  return oauthRequest(request$1, "POST /login/device/code", parameters);
}

async function exchangeDeviceCode(options) {
  const request$1 = options.request ||
  /* istanbul ignore next: we always pass a custom request in tests */
  request.request;
  const response = await oauthRequest(request$1, "POST /login/oauth/access_token", {
    client_id: options.clientId,
    device_code: options.code,
    grant_type: "urn:ietf:params:oauth:grant-type:device_code"
  });
  const authentication = {
    clientType: options.clientType,
    clientId: options.clientId,
    token: response.data.access_token,
    scopes: response.data.scope.split(/\s+/).filter(Boolean)
  };

  if ("clientSecret" in options) {
    authentication.clientSecret = options.clientSecret;
  }

  if (options.clientType === "github-app") {
    if ("refresh_token" in response.data) {
      const apiTimeInMs = new Date(response.headers.date).getTime();
      authentication.refreshToken = response.data.refresh_token, authentication.expiresAt = toTimestamp$1(apiTimeInMs, response.data.expires_in), authentication.refreshTokenExpiresAt = toTimestamp$1(apiTimeInMs, response.data.refresh_token_expires_in);
    }

    delete authentication.scopes;
  }

  return _objectSpread2(_objectSpread2({}, response), {}, {
    authentication
  });
}

function toTimestamp$1(apiTimeInMs, expirationInSeconds) {
  return new Date(apiTimeInMs + expirationInSeconds * 1000).toISOString();
}

async function checkToken(options) {
  const request$1 = options.request ||
  /* istanbul ignore next: we always pass a custom request in tests */
  request.request;
  const response = await request$1("POST /applications/{client_id}/token", {
    headers: {
      authorization: `basic ${btoa(`${options.clientId}:${options.clientSecret}`)}`
    },
    client_id: options.clientId,
    access_token: options.token
  });
  const authentication = {
    clientType: options.clientType,
    clientId: options.clientId,
    clientSecret: options.clientSecret,
    token: options.token,
    scopes: response.data.scopes
  };

  if (options.clientType === "github-app") {
    delete authentication.scopes;
  }

  return _objectSpread2(_objectSpread2({}, response), {}, {
    authentication
  });
}

async function refreshToken(options) {
  const request$1 = options.request ||
  /* istanbul ignore next: we always pass a custom request in tests */
  request.request;
  const response = await oauthRequest(request$1, "POST /login/oauth/access_token", {
    client_id: options.clientId,
    client_secret: options.clientSecret,
    grant_type: "refresh_token",
    refresh_token: options.refreshToken
  });
  const apiTimeInMs = new Date(response.headers.date).getTime();
  const authentication = {
    clientType: "github-app",
    clientId: options.clientId,
    clientSecret: options.clientSecret,
    token: response.data.access_token,
    refreshToken: response.data.refresh_token,
    expiresAt: toTimestamp$2(apiTimeInMs, response.data.expires_in),
    refreshTokenExpiresAt: toTimestamp$2(apiTimeInMs, response.data.refresh_token_expires_in)
  };
  return _objectSpread2(_objectSpread2({}, response), {}, {
    authentication
  });
}

function toTimestamp$2(apiTimeInMs, expirationInSeconds) {
  return new Date(apiTimeInMs + expirationInSeconds * 1000).toISOString();
}

async function scopeToken(options) {
  const {
    request: request$1,
    clientType,
    clientId,
    clientSecret,
    token
  } = options,
        requestOptions = _objectWithoutProperties(options, ["request", "clientType", "clientId", "clientSecret", "token"]);

  const response = await (request$1 ||
  /* istanbul ignore next: we always pass a custom request in tests */
  request.request)("POST /applications/{client_id}/token/scoped", _objectSpread2({
    headers: {
      authorization: `basic ${btoa(`${clientId}:${clientSecret}`)}`
    },
    client_id: clientId,
    access_token: token
  }, requestOptions));
  const authentication = {
    clientType,
    clientId,
    clientSecret,
    token: response.data.token
  };
  return _objectSpread2(_objectSpread2({}, response), {}, {
    authentication
  });
}

async function resetToken(options) {
  const request$1 = options.request ||
  /* istanbul ignore next: we always pass a custom request in tests */
  request.request;
  const auth = btoa(`${options.clientId}:${options.clientSecret}`);
  const response = await request$1("PATCH /applications/{client_id}/token", {
    headers: {
      authorization: `basic ${auth}`
    },
    client_id: options.clientId,
    access_token: options.token
  });
  const authentication = {
    clientType: options.clientType,
    clientId: options.clientId,
    clientSecret: options.clientSecret,
    token: response.data.token,
    scopes: response.data.scopes
  };

  if (options.clientType === "github-app") {
    delete authentication.scopes;
  }

  return _objectSpread2(_objectSpread2({}, response), {}, {
    authentication
  });
}

async function deleteToken(options) {
  const request$1 = options.request ||
  /* istanbul ignore next: we always pass a custom request in tests */
  request.request;
  const auth = btoa(`${options.clientId}:${options.clientSecret}`);
  return request$1("DELETE /applications/{client_id}/token", {
    headers: {
      authorization: `basic ${auth}`
    },
    client_id: options.clientId,
    access_token: options.token
  });
}

async function deleteAuthorization(options) {
  const request$1 = options.request ||
  /* istanbul ignore next: we always pass a custom request in tests */
  request.request;
  const auth = btoa(`${options.clientId}:${options.clientSecret}`);
  return request$1("DELETE /applications/{client_id}/grant", {
    headers: {
      authorization: `basic ${auth}`
    },
    client_id: options.clientId,
    access_token: options.token
  });
}

exports.VERSION = VERSION;
exports.checkToken = checkToken;
exports.createDeviceCode = createDeviceCode;
exports.deleteAuthorization = deleteAuthorization;
exports.deleteToken = deleteToken;
exports.exchangeDeviceCode = exchangeDeviceCode;
exports.exchangeWebFlowCode = exchangeWebFlowCode;
exports.getWebFlowAuthorizationUrl = getWebFlowAuthorizationUrl;
exports.refreshToken = refreshToken;
exports.resetToken = resetToken;
exports.scopeToken = scopeToken;
//# sourceMappingURL=index.js.map
