"use strict";

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

function _lodash() {
  const data = _interopRequireDefault(require("lodash"));

  _lodash = function () {
    return data;
  };

  return data;
}

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

  _fsExtra = function () {
    return data;
  };

  return data;
}

function _chalk() {
  const data = _interopRequireDefault(require("chalk"));

  _chalk = function () {
    return data;
  };

  return data;
}

function _ora() {
  const data = _interopRequireDefault(require("ora"));

  _ora = function () {
    return data;
  };

  return data;
}

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

  _path = function () {
    return data;
  };

  return data;
}

function _cliTable() {
  const data = _interopRequireDefault(require("cli-table"));

  _cliTable = function () {
    return data;
  };

  return data;
}

function ConfigUtils() {
  const data = _interopRequireWildcard(require("@expo/config"));

  ConfigUtils = function () {
    return data;
  };

  return data;
}

function _xdl() {
  const data = require("@expo/xdl");

  _xdl = function () {
    return data;
  };

  return data;
}

function _CommandError() {
  const data = _interopRequireDefault(require("../../CommandError"));

  _CommandError = function () {
    return data;
  };

  return data;
}

function _urlOpts() {
  const data = _interopRequireDefault(require("../../urlOpts"));

  _urlOpts = function () {
    return data;
  };

  return data;
}

function appleApi() {
  const data = _interopRequireWildcard(require("../build/ios/appleApi"));

  appleApi = function () {
    return data;
  };

  return data;
}

function _constants() {
  const data = require("../build/constants");

  _constants = function () {
    return data;
  };

  return data;
}

function _fastlane() {
  const data = require("../build/ios/appleApi/fastlane");

  _fastlane = function () {
    return data;
  };

  return data;
}

function _selectDistributionCert() {
  const data = _interopRequireDefault(require("./selectDistributionCert"));

  _selectDistributionCert = function () {
    return data;
  };

  return data;
}

function _selectPushKey() {
  const data = _interopRequireDefault(require("./selectPushKey"));

  _selectPushKey = function () {
    return data;
  };

  return data;
}

function _selectAdhocProvisioningProfile() {
  const data = _interopRequireDefault(require("./selectAdhocProvisioningProfile"));

  _selectAdhocProvisioningProfile = function () {
    return data;
  };

  return data;
}

function _generateBundleIdentifier() {
  const data = _interopRequireDefault(require("./generateBundleIdentifier"));

  _generateBundleIdentifier = function () {
    return data;
  };

  return data;
}

function _clientBuildApi() {
  const data = require("./clientBuildApi");

  _clientBuildApi = function () {
    return data;
  };

  return data;
}

function _log() {
  const data = _interopRequireDefault(require("../../log"));

  _log = function () {
    return data;
  };

  return data;
}

function _prompt() {
  const data = _interopRequireDefault(require("../../prompt"));

  _prompt = function () {
    return data;
  };

  return data;
}

function _tagger() {
  const data = require("./tagger");

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

const {
  IOS
} = _constants().PLATFORMS;

var _default = program => {
  program.command('client:ios [project-dir]').option('--apple-id <login>', 'Apple ID username (please also set the Apple ID password as EXPO_APPLE_PASSWORD environment variable).').description('Build a custom version of the Expo Client for iOS using your own Apple credentials and install it on your mobile device using Safari.').asyncActionProjectDir(async (projectDir, options) => {
    const disabledServices = {
      pushNotifications: {
        name: 'Push Notifications',
        reason: 'not yet available until API tokens are supported for the Push Notification system'
      }
    }; // get custom project manifest if it exists
    // Note: this is the current developer's project, NOT the Expo client's manifest

    const spinner = (0, _ora().default)(`Finding custom configuration for the Expo client...`).start();

    const appJsonPath = options.config || _path().default.join(projectDir, 'app.json');

    const appJsonExists = await ConfigUtils().fileExistsAsync(appJsonPath);
    const {
      exp
    } = appJsonExists ? await ConfigUtils().readConfigJsonAsync(projectDir) : {};

    if (exp) {
      spinner.succeed(`Found custom configuration for the Expo client at ${appJsonPath}`);
    } else {
      spinner.warn(`Unable to find custom configuration for the Expo client`);
    }

    if (!_lodash().default.has(exp, 'ios.config.googleMapsApiKey')) {
      const disabledReason = exp ? `ios.config.googleMapsApiKey does not exist in configuration file found in ${appJsonPath}` : 'No custom configuration file could be found. You will need to provide a json file with a valid ios.config.googleMapsApiKey field.';
      disabledServices.googleMaps = {
        name: 'Google Maps',
        reason: disabledReason
      };
    }

    if (_lodash().default.has(exp, 'ios.googleServicesFile')) {
      const contents = await _fsExtra().default.readFile(_path().default.resolve(projectDir, exp.ios.googleServicesFile), 'base64');
      exp.ios.googleServicesFile = contents;
    }

    const authData = await appleApi().authenticate(options);
    const user = await _xdl().UserManager.getCurrentUserAsync(); // check if any builds are in flight

    const {
      isAllowed,
      errorMessage
    } = await (0, _clientBuildApi().isAllowedToBuild)({
      user,
      appleTeamId: authData.team.id
    });

    if (!isAllowed) {
      throw new (_CommandError().default)('CLIENT_BUILD_REQUEST_NOT_ALLOWED', `New Expo Client build request disallowed. Reason: ${errorMessage}`);
    }

    const bundleIdentifier = (0, _generateBundleIdentifier().default)(authData.team.id);
    const experienceName = await (0, _clientBuildApi().getExperienceName)({
      user,
      appleTeamId: authData.team.id
    });
    const context = { ...authData,
      bundleIdentifier,
      experienceName,
      username: user ? user.username : null
    };
    await appleApi().ensureAppExists(context, {
      enablePushNotifications: true
    });
    const {
      devices
    } = await (0, _fastlane().runAction)(_fastlane().travelingFastlane.listDevices, ['--all-ios-profile-devices', context.appleId, context.appleIdPassword, context.team.id]);
    const udids = devices.map(device => device.deviceNumber);
    const distributionCert = await (0, _selectDistributionCert().default)(context);
    const pushKey = await (0, _selectPushKey().default)(context);
    const provisioningProfile = await (0, _selectAdhocProvisioningProfile().default)(context, udids, distributionCert.distCertSerialNumber); // push notifications won't work if we dont have any push creds
    // we also dont store anonymous creds, so user needs to be logged in

    if (pushKey === null || !user) {
      const disabledReason = pushKey === null ? 'you did not upload your push credentials' : 'we require you to be logged in to store push credentials'; // TODO(quin): remove this when we fix push notifications
      // keep the default push notification reason if we haven't implemented API tokens

      disabledServices.pushNotifications.reason = disabledServices.pushNotifications.reason || disabledReason;
    }

    if (Object.keys(disabledServices).length > 0) {
      _log().default.newLine();

      _log().default.warn('These services will be disabled in your custom Expo Client:');

      const table = new (_cliTable().default)({
        head: ['Service', 'Reason'],
        style: {
          head: ['cyan']
        }
      });
      table.push(...Object.keys(disabledServices).map(serviceKey => {
        const service = disabledServices[serviceKey];
        return [service.name, service.reason];
      }));
      (0, _log().default)(table.toString());
      (0, _log().default)('See https://docs.expo.io/versions/latest/guides/adhoc-builds/#optional-additional-configuration-steps for more details.');
    } // if user is logged in, then we should update credentials


    const credentialsList = [distributionCert, pushKey, provisioningProfile].filter(i => i);

    if (user) {
      // store all the credentials that we mark for update
      const updateCredentialsFn = async listOfCredentials => {
        if (listOfCredentials.length === 0) {
          return;
        }

        const credentials = listOfCredentials.reduce((acc, credential) => {
          return { ...acc,
            ...credential
          };
        }, {
          teamId: context.team.id
        });
        await _xdl().Credentials.updateCredentialsForPlatform(IOS, credentials, [], {
          username: user.username,
          experienceName,
          bundleIdentifier
        });
      };

      const CredentialsUpdater = new (_tagger().Updater)(updateCredentialsFn);
      await CredentialsUpdater.updateAllAsync(credentialsList);
    } else {
      // clear update tags, we dont store credentials for anonymous users
      (0, _tagger().clearTags)(credentialsList);
    }

    let email;

    if (user) {
      email = user.email;
    } else {
      ({
        email
      } = await (0, _prompt().default)({
        name: 'email',
        message: 'Please enter an email address to notify, when the build is completed:',
        filter: value => value.trim(),
        validate: value => /.+@.+/.test(value) ? true : "That doesn't look like a valid email."
      }));
    }

    _log().default.newLine();

    let addUdid;

    if (udids.length === 0) {
      (0, _log().default)('There are no devices registered to your Apple Developer account. Please follow the instructions below to register an iOS device.');
      addUdid = true;
    } else {
      (0, _log().default)('Custom builds of the Expo Client can only be installed on devices which have been registered with Apple at build-time.');
      (0, _log().default)('These devices are currently registered on your Apple Developer account:');
      const table = new (_cliTable().default)({
        head: ['Name', 'Identifier'],
        style: {
          head: ['cyan']
        }
      });
      table.push(...devices.map(device => [device.name, device.deviceNumber]));
      (0, _log().default)(table.toString());
      const udidPrompt = await (0, _prompt().default)({
        name: 'addUdid',
        message: 'Would you like to register a new device to use the Expo Client with?',
        type: 'confirm',
        default: true
      });
      addUdid = udidPrompt.addUdid;
    }

    const result = await (0, _clientBuildApi().createClientBuildRequest)({
      user,
      context,
      distributionCert,
      provisioningProfile,
      pushKey,
      udids,
      addUdid,
      email,
      customAppConfig: exp
    });

    _log().default.newLine();

    if (addUdid) {
      _urlOpts().default.printQRCode(result.registrationUrl);

      (0, _log().default)('Open the following link on your iOS device (or scan the QR code) and follow the instructions to install the development profile:');

      _log().default.newLine();

      (0, _log().default)(_chalk().default.green(`${result.registrationUrl}`));

      _log().default.newLine();

      (0, _log().default)('Please note that you can only register one iOS device per request.');
      (0, _log().default)("After you register your device, we'll start building your client, and you'll receive an email when it's ready to install.");
    } else {
      _urlOpts().default.printQRCode(result.statusUrl);

      (0, _log().default)('Your custom Expo Client is being built! 🛠');
      (0, _log().default)('Open this link on your iOS device (or scan the QR code) to view build logs and install the client:');

      _log().default.newLine();

      (0, _log().default)(_chalk().default.green(`${result.statusUrl}`));
    }

    _log().default.newLine();
  }, true);
  program.command('client:install:ios').description('Install the latest version of Expo Client for iOS on the simulator').asyncAction(async () => {
    if (await _xdl().Simulator.upgradeExpoAsync()) {
      (0, _log().default)('Done!');
    }
  }, true);
  program.command('client:install:android').description('Install the latest version of Expo Client for Android on a connected device or emulator').asyncAction(async () => {
    if (await _xdl().Android.upgradeExpoAsync()) {
      (0, _log().default)('Done!');
    }
  }, true);
};

exports.default = _default;
//# sourceMappingURL=../../__sourcemaps__/commands/client/index.js.map