"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