@expo/xdl
Version:
The Expo Development Library
462 lines (360 loc) • 13.5 kB
JavaScript
;
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