You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

235 lines
7.6 KiB

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getManifestHandler = getManifestHandler;
exports.getManifestResponseAsync = getManifestResponseAsync;
function _config() {
const data = require("@expo/config");
_config = function () {
return data;
};
return data;
}
function _configPlugins() {
const data = require("@expo/config-plugins");
_configPlugins = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _nullthrows() {
const data = _interopRequireDefault(require("nullthrows"));
_nullthrows = function () {
return data;
};
return data;
}
function _url() {
const data = require("url");
_url = function () {
return data;
};
return data;
}
function _uuid() {
const data = require("uuid");
_uuid = function () {
return data;
};
return data;
}
function _internal() {
const data = require("../internal");
_internal = function () {
return data;
};
return data;
}
function _ManifestHandler() {
const data = require("./ManifestHandler");
_ManifestHandler = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function getPlatformFromRequest(req) {
const url = req.url ? (0, _url().parse)(req.url, /* parseQueryString */true) : null;
const platform = (url === null || url === void 0 ? void 0 : url.query.platform) || req.headers['expo-platform'];
if (!platform) {
throw new Error('Must specify expo-platform header or query parameter');
}
const stringifiedPlatform = String(platform);
if (!['android', 'ios'].includes(stringifiedPlatform)) {
throw new Error(`platform must be "android" or "ios". Recieved: "${platform}"`);
}
return stringifiedPlatform;
}
/**
* Whether an anonymous scope key should be used. It should be used when:
* 1. Offline
* 2. Not logged-in
* 3. No EAS project ID in config
*/
async function shouldUseAnonymousManifestAsync(easProjectId) {
if (!easProjectId || _internal().ConnectionStatus.isOffline()) {
return true;
}
const currentSession = await _internal().UserManager.getSessionAsync();
if (!currentSession) {
return true;
}
return false;
}
async function getScopeKeyForProjectIdAsync(projectId) {
const user = await _internal().UserManager.ensureLoggedInAsync();
const project = await _internal().ApiV2.clientForUser(user).getAsync(`projects/${encodeURIComponent(projectId)}`);
return project.scopeKey;
}
async function signManifestAsync(manifest) {
const user = await _internal().UserManager.ensureLoggedInAsync();
const {
signature
} = await _internal().ApiV2.clientForUser(user).postAsync('manifest/eas/sign', {
manifest: manifest
});
return signature;
}
async function getManifestResponseAsync({
projectRoot,
platform,
host,
acceptSignature
}) {
var _expoConfig$runtimeVe, _expoConfig$extra, _expoConfig$extra$eas;
const headers = new Map();
// set required headers for Expo Updates manifest specification
headers.set('expo-protocol-version', 0);
headers.set('expo-sfv-version', 0);
headers.set('cache-control', 'private, max-age=0');
headers.set('content-type', 'application/json');
const hostname = (0, _ManifestHandler().stripPort)(host);
const [projectSettings, bundleUrlPackagerOpts] = await (0, _ManifestHandler().getPackagerOptionsAsync)(projectRoot);
const projectConfig = (0, _config().getConfig)(projectRoot);
const entryPoint = (0, _internal().resolveEntryPoint)(projectRoot, platform, projectConfig);
const mainModuleName = _internal().UrlUtils.stripJSExtension(entryPoint);
const expoConfig = projectConfig.exp;
const expoGoConfig = await (0, _ManifestHandler().getExpoGoConfig)({
projectRoot,
projectSettings,
mainModuleName,
hostname
});
const hostUri = await _internal().UrlUtils.constructHostUriAsync(projectRoot, hostname);
const runtimeVersion = _configPlugins().Updates.getRuntimeVersion({
...expoConfig,
runtimeVersion: (_expoConfig$runtimeVe = expoConfig.runtimeVersion) !== null && _expoConfig$runtimeVe !== void 0 ? _expoConfig$runtimeVe : {
policy: 'sdkVersion'
}
}, platform);
if (!runtimeVersion) {
throw new Error(`Unable to determine runtime version for ${platform}`);
}
const bundleUrl = await (0, _ManifestHandler().getBundleUrlAsync)({
projectRoot,
platform,
projectSettings,
bundleUrlPackagerOpts,
mainModuleName,
hostname
});
await _internal().ProjectAssets.resolveManifestAssets({
projectRoot,
manifest: expoConfig,
async resolver(path) {
return bundleUrl.match(/^https?:\/\/.*?\//)[0] + 'assets/' + path;
}
});
const easProjectId = (_expoConfig$extra = expoConfig.extra) === null || _expoConfig$extra === void 0 ? void 0 : (_expoConfig$extra$eas = _expoConfig$extra.eas) === null || _expoConfig$extra$eas === void 0 ? void 0 : _expoConfig$extra$eas.projectId;
const shouldUseAnonymousManifest = await shouldUseAnonymousManifestAsync(easProjectId);
const userAnonymousIdentifier = await _internal().UserSettings.getAnonymousIdentifierAsync();
const scopeKey = shouldUseAnonymousManifest ? `@${_internal().ANONYMOUS_USERNAME}/${expoConfig.slug}-${userAnonymousIdentifier}` : await getScopeKeyForProjectIdAsync((0, _nullthrows().default)(easProjectId));
const expoUpdatesManifest = {
id: (0, _uuid().v4)(),
createdAt: new Date().toISOString(),
runtimeVersion,
launchAsset: {
key: 'bundle',
contentType: 'application/javascript',
url: bundleUrl
},
assets: [],
// assets are not used in development
metadata: {},
// required for the client to detect that this is an expo-updates manifest
extra: {
eas: {
projectId: easProjectId !== null && easProjectId !== void 0 ? easProjectId : undefined
},
expoClient: {
...expoConfig,
hostUri
},
expoGo: expoGoConfig,
scopeKey
}
};
if (acceptSignature && !shouldUseAnonymousManifest) {
const manifestSignature = await signManifestAsync(expoUpdatesManifest);
headers.set('expo-manifest-signature', manifestSignature);
}
return {
body: expoUpdatesManifest,
headers
};
}
function getManifestHandler(projectRoot) {
return async (req, res, next) => {
// Only support `/`, `/manifest`, `/index.exp` for the manifest middleware.
if (!req.url || !['/', '/manifest', '/index.exp'].includes(
// Strip the query params
(0, _url().parse)(req.url).pathname || req.url)) {
next();
return;
}
if (_internal().Env.isDebug()) {
console.log(_chalk().default.gray(`Manifest request: URL "${req.url}", Headers ${JSON.stringify(req.headers)}`));
}
try {
const {
body,
headers
} = await getManifestResponseAsync({
projectRoot,
host: req.headers.host,
platform: getPlatformFromRequest(req),
acceptSignature: !!req.headers['expo-accept-signature']
});
for (const [headerName, headerValue] of headers) {
res.setHeader(headerName, headerValue);
}
res.end(JSON.stringify(body));
_internal().Analytics.logEvent('Serve Expo Updates Manifest', {
developerTool: _internal().Config.developerTool,
runtimeVersion: body.runtimeVersion
});
} catch (e) {
_internal().ProjectUtils.logError(projectRoot, 'expo', e.stack);
res.statusCode = 520;
res.end(JSON.stringify({
error: e.toString()
}));
}
};
}
//# sourceMappingURL=ExpoUpdatesManifestHandler.js.map