UNPKG

@expo/xdl

Version:
462 lines (360 loc) 13.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getManifestHandler = getManifestHandler; exports.getManifestResponseAsync = getManifestResponseAsync; exports.getSignedManifestStringAsync = getSignedManifestStringAsync; exports.getUnsignedManifestString = getUnsignedManifestString; function _config() { const data = require("@expo/config"); _config = function () { return data; }; return data; } function _chalk() { const data = _interopRequireDefault(require("chalk")); _chalk = function () { return data; }; return data; } function _os() { const data = _interopRequireDefault(require("os")); _os = function () { return data; }; return data; } function _url() { const data = require("url"); _url = function () { return data; }; return data; } function _Analytics() { const data = _interopRequireDefault(require("../Analytics")); _Analytics = function () { return data; }; return data; } function _ApiV() { const data = _interopRequireDefault(require("../ApiV2")); _ApiV = function () { return data; }; return data; } function _Config() { const data = _interopRequireDefault(require("../Config")); _Config = function () { return data; }; return data; } function _ProjectAssets() { const data = require("../ProjectAssets"); _ProjectAssets = function () { return data; }; return data; } function ProjectSettings() { const data = _interopRequireWildcard(require("../ProjectSettings")); ProjectSettings = function () { return data; }; return data; } function UrlUtils() { const data = _interopRequireWildcard(require("../UrlUtils")); UrlUtils = function () { return data; }; return data; } function _User() { const data = _interopRequireWildcard(require("../User")); _User = function () { return data; }; return data; } function _UserSettings() { const data = _interopRequireDefault(require("../UserSettings")); _UserSettings = function () { return data; }; return data; } function Versions() { const data = _interopRequireWildcard(require("../Versions")); Versions = function () { return data; }; return data; } function _TerminalLink() { const data = require("../logs/TerminalLink"); _TerminalLink = function () { return data; }; return data; } function Doctor() { const data = _interopRequireWildcard(require("../project/Doctor")); Doctor = function () { return data; }; return data; } function ProjectUtils() { const data = _interopRequireWildcard(require("../project/ProjectUtils")); ProjectUtils = function () { return data; }; return data; } function _resolveEntryPoint() { const data = require("../tools/resolveEntryPoint"); _resolveEntryPoint = function () { return data; }; return data; } function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const _cachedSignedManifest = { manifestString: null, signedManifest: null }; const blacklistedEnvironmentVariables = new Set(['EXPO_APPLE_PASSWORD', 'EXPO_ANDROID_KEY_PASSWORD', 'EXPO_ANDROID_KEYSTORE_PASSWORD', 'EXPO_IOS_DIST_P12_PASSWORD', 'EXPO_IOS_PUSH_P12_PASSWORD', 'EXPO_CLI_PASSWORD']); function shouldExposeEnvironmentVariableInManifest(key) { if (blacklistedEnvironmentVariables.has(key.toUpperCase())) { return false; } return key.startsWith('REACT_NATIVE_') || key.startsWith('EXPO_'); } function stripPort(host) { if (!host) { return host; } return new (_url().URL)('/', `http://${host}`).hostname; } async function getPackagerOptionsAsync(projectRoot) { // Get packager opts and then copy into bundleUrlPackagerOpts const projectSettings = await ProjectSettings().readAsync(projectRoot); const bundleUrlPackagerOpts = JSON.parse(JSON.stringify(projectSettings)); bundleUrlPackagerOpts.urlType = 'http'; if (bundleUrlPackagerOpts.hostType === 'redirect') { bundleUrlPackagerOpts.hostType = 'tunnel'; } return [projectSettings, bundleUrlPackagerOpts]; } async function getBundleUrlAsync({ projectRoot, platform, projectSettings, bundleUrlPackagerOpts, mainModuleName, hostname }) { const queryParams = UrlUtils().constructBundleQueryParams(projectRoot, projectSettings); const path = `/${encodeURI(mainModuleName)}.bundle?platform=${encodeURIComponent(platform)}&${queryParams}`; return (await UrlUtils().constructBundleUrlAsync(projectRoot, bundleUrlPackagerOpts, hostname)) + path; } function getPlatformFromRequest(headers) { return (headers['exponent-platform'] || 'ios').toString(); } function getManifestHandler(projectRoot) { return async (req, res) => { try { var _exp$sdkVersion; // We intentionally don't `await`. We want to continue trying even // if there is a potential error in the package.json and don't want to slow // down the request Doctor().validateWithNetworkAsync(projectRoot).catch(error => { ProjectUtils().logError(projectRoot, 'expo', `Error: could not load config json at ${projectRoot}: ${error.toString()}`, 'doctor-config-json-not-read'); }); const { manifestString, exp, hostInfo } = await getManifestResponseFromHeadersAsync({ projectRoot, headers: req.headers }); const sdkVersion = (_exp$sdkVersion = exp.sdkVersion) !== null && _exp$sdkVersion !== void 0 ? _exp$sdkVersion : null; // Send the response res.setHeader('Exponent-Server', JSON.stringify(hostInfo)); // End the request res.end(manifestString); // Log analytics _Analytics().default.logEvent('Serve Manifest', { projectRoot, developerTool: _Config().default.developerTool, sdkVersion }); } catch (e) { ProjectUtils().logError(projectRoot, 'expo', e.stack); // 5xx = Server Error HTTP code res.statusCode = 520; res.end(JSON.stringify({ error: e.toString() })); } }; } async function getManifestResponseFromHeadersAsync({ projectRoot, headers }) { // Read from headers const platform = getPlatformFromRequest(headers); const acceptSignature = headers['exponent-accept-signature']; return getManifestResponseAsync({ projectRoot, host: headers.host, platform, acceptSignature }); } async function getManifestResponseAsync({ projectRoot, host, platform, acceptSignature }) { // Read the config const projectConfig = (0, _config().getConfig)(projectRoot); const manifest = projectConfig.exp; // Read from headers const hostname = stripPort(host); // Get project entry point and initial module const entryPoint = (0, _resolveEntryPoint().resolveEntryPoint)(projectRoot, platform, projectConfig); const mainModuleName = UrlUtils().stripJSExtension(entryPoint); // Gather packager and host info const hostInfo = await createHostInfoAsync(); const [projectSettings, bundleUrlPackagerOpts] = await getPackagerOptionsAsync(projectRoot); // Mutate the manifest manifest.xde = true; // deprecated manifest.developer = { tool: _Config().default.developerTool, projectRoot }; manifest.packagerOpts = projectSettings; manifest.mainModuleName = mainModuleName; // Adding the env variables to the Expo manifest is unsafe. // This feature is deprecated in SDK 41 forward. if (manifest.sdkVersion && Versions().lteSdkVersion(manifest, '40.0.0')) { manifest.env = getManifestEnvironment(); } // Add URLs to the manifest manifest.bundleUrl = await getBundleUrlAsync({ projectRoot, platform, projectSettings, bundleUrlPackagerOpts, mainModuleName, hostname }); manifest.debuggerHost = await UrlUtils().constructDebuggerHostAsync(projectRoot, hostname); manifest.logUrl = await UrlUtils().constructLogUrlAsync(projectRoot, hostname); manifest.hostUri = await UrlUtils().constructHostUriAsync(projectRoot, hostname); // Resolve all assets and set them on the manifest as URLs await (0, _ProjectAssets().resolveManifestAssets)({ projectRoot, manifest: manifest, async resolver(path) { return manifest.bundleUrl.match(/^https?:\/\/.*?\//)[0] + 'assets/' + path; } }); // The server normally inserts this but if we're offline we'll do it here await (0, _ProjectAssets().resolveGoogleServicesFile)(projectRoot, manifest); // Create the final string let manifestString; try { manifestString = await getManifestStringAsync(manifest, hostInfo.host, acceptSignature); } catch (error) { if (error.code === 'UNAUTHORIZED_ERROR' && manifest.owner) { // Don't have permissions for siging, warn and enable offline mode. addSigningDisabledWarning(projectRoot, `This project belongs to ${_chalk().default.bold(`@${manifest.owner}`)} and you have not been granted the appropriate permissions.\n` + `Please request access from an admin of @${manifest.owner} or change the "owner" field to an account you belong to.\n` + (0, _TerminalLink().learnMore)('https://docs.expo.io/versions/latest/config/app/#owner')); _Config().default.offline = true; manifestString = await getManifestStringAsync(manifest, hostInfo.host, acceptSignature); } else if (error.code === 'ENOTFOUND') { // Got a DNS error, i.e. can't access exp.host, warn and enable offline mode. addSigningDisabledWarning(projectRoot, `Could not reach Expo servers, please check if you can access ${error.hostname || 'exp.host'}.`); _Config().default.offline = true; manifestString = await getManifestStringAsync(manifest, hostInfo.host, acceptSignature); } else { throw error; } } return { manifestString, exp: manifest, hostInfo }; } const addSigningDisabledWarning = (() => { let seen = false; return (projectRoot, reason) => { if (!seen) { seen = true; ProjectUtils().logWarning(projectRoot, 'expo', `${reason}\nFalling back to offline mode.`, 'signing-disabled'); } }; })(); function getManifestEnvironment() { return Object.keys(process.env).reduce((prev, key) => { if (shouldExposeEnvironmentVariableInManifest(key)) { prev[key] = process.env[key]; } return prev; }, {}); } async function getManifestStringAsync(manifest, hostUUID, acceptSignature) { const currentSession = await _User().default.getSessionAsync(); if (!currentSession || _Config().default.offline) { manifest.id = `@${_User().ANONYMOUS_USERNAME}/${manifest.slug}-${hostUUID}`; } if (!acceptSignature) { return JSON.stringify(manifest); } else if (!currentSession || _Config().default.offline) { return getUnsignedManifestString(manifest); } else { return await getSignedManifestStringAsync(manifest, currentSession); } } async function createHostInfoAsync() { const host = await _UserSettings().default.anonymousIdentifier(); return { host, server: 'xdl', serverVersion: require('@expo/xdl/package.json').version, serverDriver: _Config().default.developerTool, serverOS: _os().default.platform(), serverOSVersion: _os().default.release() }; } async function getSignedManifestStringAsync(manifest, // NOTE: we currently ignore the currentSession that is passed in, see the note below about analytics. currentSession) { var _manifest$owner; const manifestString = JSON.stringify(manifest); if (_cachedSignedManifest.manifestString === manifestString) { return _cachedSignedManifest.signedManifest; } // WARNING: Removing the following line will regress analytics, see: https://github.com/expo/expo-cli/pull/2357 // TODO: make this more obvious from code const user = await _User().default.ensureLoggedInAsync(); const { response } = await _ApiV().default.clientForUser(user).postAsync('manifest/sign', { args: { remoteUsername: (_manifest$owner = manifest.owner) !== null && _manifest$owner !== void 0 ? _manifest$owner : await _User().default.getCurrentUsernameAsync(), remotePackageName: manifest.slug }, manifest: manifest }); _cachedSignedManifest.manifestString = manifestString; _cachedSignedManifest.signedManifest = response; return response; } function getUnsignedManifestString(manifest) { const unsignedManifest = { manifestString: JSON.stringify(manifest), signature: 'UNSIGNED' }; return JSON.stringify(unsignedManifest); } //# sourceMappingURL=../__sourcemaps__/start/ManifestHandler.js.map