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.
426 lines
16 KiB
426 lines
16 KiB
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.constructAssetsUrlAsync = constructAssetsUrlAsync;
|
|
exports.constructBundleQueryParams = constructBundleQueryParams;
|
|
exports.constructBundleQueryParamsWithConfig = constructBundleQueryParamsWithConfig;
|
|
exports.constructBundleUrlAsync = constructBundleUrlAsync;
|
|
exports.constructDebuggerHostAsync = constructDebuggerHostAsync;
|
|
exports.constructDeepLinkAsync = constructDeepLinkAsync;
|
|
exports.constructDevClientUrlAsync = constructDevClientUrlAsync;
|
|
exports.constructHostUriAsync = constructHostUriAsync;
|
|
exports.constructLoadingUrlAsync = constructLoadingUrlAsync;
|
|
exports.constructLogUrlAsync = constructLogUrlAsync;
|
|
exports.constructManifestUrlAsync = constructManifestUrlAsync;
|
|
exports.constructPublishUrlAsync = constructPublishUrlAsync;
|
|
exports.constructSourceMapUrlAsync = constructSourceMapUrlAsync;
|
|
exports.constructUrlAsync = constructUrlAsync;
|
|
exports.constructUrlWithExtensionAsync = constructUrlWithExtensionAsync;
|
|
exports.constructWebAppUrlAsync = constructWebAppUrlAsync;
|
|
exports.isHttps = isHttps;
|
|
exports.isURL = isURL;
|
|
exports.stripJSExtension = stripJSExtension;
|
|
function _config() {
|
|
const data = require("@expo/config");
|
|
_config = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _assert() {
|
|
const data = _interopRequireDefault(require("assert"));
|
|
_assert = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _os() {
|
|
const data = _interopRequireDefault(require("os"));
|
|
_os = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _querystring() {
|
|
const data = _interopRequireDefault(require("querystring"));
|
|
_querystring = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _resolveFrom() {
|
|
const data = _interopRequireDefault(require("resolve-from"));
|
|
_resolveFrom = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _url() {
|
|
const data = _interopRequireDefault(require("url"));
|
|
_url = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _internal() {
|
|
const data = require("./internal");
|
|
_internal = function () {
|
|
return data;
|
|
};
|
|
return data;
|
|
}
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
async function constructBundleUrlAsync(projectRoot, opts, requestHostname) {
|
|
return await constructUrlAsync(projectRoot, opts, true, requestHostname);
|
|
}
|
|
async function constructDeepLinkAsync(projectRoot, opts, requestHostname) {
|
|
const {
|
|
devClient
|
|
} = await _internal().ProjectSettings.readAsync(projectRoot);
|
|
if (devClient) {
|
|
return constructDevClientUrlAsync(projectRoot, opts, requestHostname);
|
|
} else {
|
|
return constructManifestUrlAsync(projectRoot, opts, requestHostname);
|
|
}
|
|
}
|
|
async function constructManifestUrlAsync(projectRoot, opts, requestHostname) {
|
|
return await constructUrlAsync(projectRoot, opts !== null && opts !== void 0 ? opts : null, false, requestHostname);
|
|
}
|
|
async function constructDevClientUrlAsync(projectRoot, opts, requestHostname) {
|
|
let _scheme;
|
|
if (opts !== null && opts !== void 0 && opts.scheme) {
|
|
_scheme = opts === null || opts === void 0 ? void 0 : opts.scheme;
|
|
} else {
|
|
const {
|
|
scheme
|
|
} = await _internal().ProjectSettings.readAsync(projectRoot);
|
|
if (!scheme || typeof scheme !== 'string') {
|
|
throw new (_internal().XDLError)('NO_DEV_CLIENT_SCHEME', 'No scheme specified for development client');
|
|
}
|
|
_scheme = scheme;
|
|
}
|
|
const protocol = resolveProtocol(projectRoot, {
|
|
scheme: _scheme,
|
|
urlType: 'custom'
|
|
});
|
|
const manifestUrl = await constructManifestUrlAsync(projectRoot, {
|
|
...opts,
|
|
urlType: 'http'
|
|
}, requestHostname);
|
|
return `${protocol}://expo-development-client/?url=${encodeURIComponent(manifestUrl)}`;
|
|
}
|
|
|
|
// gets the base manifest URL and removes the scheme
|
|
async function constructHostUriAsync(projectRoot, requestHostname) {
|
|
const urlString = await constructUrlAsync(projectRoot, null, false, requestHostname);
|
|
// we need to use node's legacy urlObject api since the newer one doesn't like empty protocols
|
|
const urlObj = _url().default.parse(urlString);
|
|
urlObj.protocol = '';
|
|
urlObj.slashes = false;
|
|
return _url().default.format(urlObj);
|
|
}
|
|
async function constructLogUrlAsync(projectRoot, requestHostname) {
|
|
const baseUrl = await constructUrlAsync(projectRoot, {
|
|
urlType: 'http'
|
|
}, false, requestHostname);
|
|
return `${baseUrl}/logs`;
|
|
}
|
|
async function constructLoadingUrlAsync(projectRoot, platform, requestHostname) {
|
|
const baseUrl = await constructUrlAsync(projectRoot, {
|
|
urlType: 'http'
|
|
}, false, requestHostname);
|
|
const query = platform ? `?platform=${platform}` : '';
|
|
return `${baseUrl}/_expo/loading${query}`;
|
|
}
|
|
async function constructUrlWithExtensionAsync(projectRoot, entryPoint, ext, requestHostname, metroQueryOptions) {
|
|
const defaultOpts = {
|
|
dev: false,
|
|
minify: true
|
|
};
|
|
metroQueryOptions = metroQueryOptions || defaultOpts;
|
|
let bundleUrl = await constructBundleUrlAsync(projectRoot, {
|
|
hostType: 'localhost',
|
|
urlType: 'http'
|
|
}, requestHostname);
|
|
const mainModulePath = stripJSExtension(entryPoint);
|
|
bundleUrl += `/${mainModulePath}.${ext}`;
|
|
const queryParams = constructBundleQueryParams(projectRoot, metroQueryOptions);
|
|
return `${bundleUrl}?${queryParams}`;
|
|
}
|
|
async function constructPublishUrlAsync(projectRoot, entryPoint, requestHostname, metroQueryOptions) {
|
|
return await constructUrlWithExtensionAsync(projectRoot, entryPoint, 'bundle', requestHostname, metroQueryOptions);
|
|
}
|
|
async function constructSourceMapUrlAsync(projectRoot, entryPoint, requestHostname) {
|
|
return await constructUrlWithExtensionAsync(projectRoot, entryPoint, 'map', requestHostname);
|
|
}
|
|
async function constructAssetsUrlAsync(projectRoot, entryPoint, requestHostname) {
|
|
return await constructUrlWithExtensionAsync(projectRoot, entryPoint, 'assets', requestHostname);
|
|
}
|
|
async function constructDebuggerHostAsync(projectRoot, requestHostname) {
|
|
return await constructUrlAsync(projectRoot, {
|
|
urlType: 'no-protocol'
|
|
}, true, requestHostname);
|
|
}
|
|
function constructBundleQueryParams(projectRoot, opts) {
|
|
// No SDK Version will assume the latest requirements
|
|
const {
|
|
exp
|
|
} = (0, _config().getConfig)(projectRoot, {
|
|
skipSDKVersionRequirement: true
|
|
});
|
|
return constructBundleQueryParamsWithConfig(projectRoot, opts, exp);
|
|
}
|
|
function constructBundleQueryParamsWithConfig(projectRoot, opts, exp) {
|
|
const queryParams = {
|
|
dev: !!opts.dev,
|
|
hot: false
|
|
};
|
|
if ('strict' in opts) {
|
|
queryParams.strict = !!opts.strict;
|
|
}
|
|
if ('minify' in opts) {
|
|
// TODO: Maybe default this to true if dev is false
|
|
queryParams.minify = !!opts.minify;
|
|
}
|
|
|
|
// TODO: Remove this ...
|
|
|
|
// SDK11 to SDK32 require us to inject hashAssetFiles through the params, but this is not
|
|
// needed with SDK33+
|
|
if (_internal().Versions.lteSdkVersion(exp, '10.0.0')) {
|
|
// SDK <=10
|
|
// Only sdk-10.1.0+ supports the assetPlugin parameter. We use only the
|
|
// major version in the sdkVersion field, so check for 11.0.0 to be sure.
|
|
queryParams.includeAssetFileHashes = true;
|
|
} else if (_internal().Versions.lteSdkVersion(exp, '32.0.0')) {
|
|
// SDK 11-32
|
|
// Use an absolute path here so that we can not worry about symlinks/relative requires
|
|
const pluginModule = (0, _resolveFrom().default)(projectRoot, 'expo/tools/hashAssetFiles');
|
|
queryParams.assetPlugin = encodeURIComponent(pluginModule);
|
|
}
|
|
// Special requirements aren't needed after SDK 33 (Jun 5 2019)
|
|
|
|
return _querystring().default.stringify(queryParams);
|
|
}
|
|
async function constructWebAppUrlAsync(projectRoot, options = {}) {
|
|
var _options$hostType;
|
|
const packagerInfo = await _internal().ProjectSettings.readPackagerInfoAsync(projectRoot);
|
|
if (!packagerInfo.webpackServerPort) {
|
|
return null;
|
|
}
|
|
const {
|
|
https,
|
|
hostType
|
|
} = await _internal().ProjectSettings.readAsync(projectRoot);
|
|
const host = ((_options$hostType = options.hostType) !== null && _options$hostType !== void 0 ? _options$hostType : hostType) === 'localhost' ? 'localhost' : _internal().ip.address();
|
|
let urlType = 'http';
|
|
if (https === true) {
|
|
urlType = 'https';
|
|
}
|
|
return `${urlType}://${host}:${packagerInfo.webpackServerPort}`;
|
|
}
|
|
function assertValidOptions(opts) {
|
|
if (opts.devClient && typeof opts.devClient !== 'boolean') {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"devClient" must be a boolean if specified`);
|
|
}
|
|
if (opts.scheme && typeof opts.scheme !== 'string') {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"scheme" must be a string if specified`);
|
|
}
|
|
if (![undefined, null, 'exp', 'http', 'redirect', 'no-protocol'].includes(opts.urlType)) {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"urlType" must be one of: "exp", "http", "redirect", "no-protocol" if specified`);
|
|
}
|
|
if (![undefined, 'ip', 'hostname'].includes(opts.lanType)) {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"lanType" must be one of: "ip", "hostname" if specified`);
|
|
}
|
|
if (![undefined, 'localhost', 'lan', 'tunnel'].includes(opts.hostType)) {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"hostType" must be one of: "localhost", "lan", "tunnel" if specified`);
|
|
}
|
|
if (opts.dev && typeof opts.dev !== 'boolean') {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"dev" must be a boolean if specified`);
|
|
}
|
|
if (opts.strict && typeof opts.strict !== 'boolean') {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"strict" must be a boolean if specified`);
|
|
}
|
|
if (opts.minify && typeof opts.minify !== 'boolean') {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"minify" must be a boolean if specified`);
|
|
}
|
|
if (opts.https && typeof opts.https !== 'boolean') {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"https" must be a boolean if specified`);
|
|
}
|
|
if (opts.urlRandomness && typeof opts.urlRandomness !== 'string') {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"urlRandomness" must be a string if specified`);
|
|
}
|
|
Object.keys(opts).forEach(key => {
|
|
if (!['devClient', 'scheme', 'urlType', 'lanType', 'hostType', 'dev', 'strict', 'minify', 'https', 'urlRandomness'].includes(key)) {
|
|
throw new (_internal().XDLError)('INVALID_OPTIONS', `"${key}" is not a valid option`);
|
|
}
|
|
});
|
|
return opts;
|
|
}
|
|
async function ensureOptionsAsync(projectRoot, opts) {
|
|
if (opts) {
|
|
assertValidOptions(opts);
|
|
}
|
|
const defaultOpts = await _internal().ProjectSettings.readAsync(projectRoot);
|
|
if (!opts) {
|
|
return {
|
|
urlType: null,
|
|
...defaultOpts
|
|
};
|
|
}
|
|
const optionsWithDefaults = {
|
|
...defaultOpts,
|
|
...opts
|
|
};
|
|
return assertValidOptions(optionsWithDefaults);
|
|
}
|
|
function resolveProtocol(projectRoot, {
|
|
urlType,
|
|
...options
|
|
}) {
|
|
if (urlType === 'http') {
|
|
return 'http';
|
|
} else if (urlType === 'no-protocol') {
|
|
return null;
|
|
} else if (urlType === 'custom') {
|
|
return options.scheme;
|
|
}
|
|
let protocol = 'exp';
|
|
const {
|
|
exp
|
|
} = (0, _config().getConfig)(projectRoot, {
|
|
skipSDKVersionRequirement: true
|
|
});
|
|
|
|
// We only use these values from the config
|
|
const {
|
|
scheme,
|
|
detach,
|
|
sdkVersion
|
|
} = exp;
|
|
if (detach) {
|
|
// Normalize schemes and filter invalid schemes.
|
|
const schemes = (Array.isArray(scheme) ? scheme : [scheme]).filter(scheme => typeof scheme === 'string' && !!scheme);
|
|
// Get the first valid scheme.
|
|
const firstScheme = schemes[0];
|
|
if (firstScheme && !_internal().Versions.lteSdkVersion({
|
|
sdkVersion
|
|
}, '26.0.0')) {
|
|
protocol = firstScheme;
|
|
} else if (detach.scheme) {
|
|
// must keep this fallback in place for older projects
|
|
// and those detached with an older version of xdl
|
|
protocol = detach.scheme;
|
|
}
|
|
}
|
|
return protocol;
|
|
}
|
|
async function constructUrlAsync(projectRoot, incomingOpts, isPackager, requestHostname) {
|
|
const opts = await ensureOptionsAsync(projectRoot, incomingOpts);
|
|
const packagerInfo = await _internal().ProjectSettings.readPackagerInfoAsync(projectRoot);
|
|
let protocol = resolveProtocol(projectRoot, opts);
|
|
let hostname;
|
|
let port;
|
|
const proxyURL = isPackager ? process.env.EXPO_PACKAGER_PROXY_URL : process.env.EXPO_MANIFEST_PROXY_URL;
|
|
if (proxyURL) {
|
|
const parsedProxyURL = _url().default.parse(proxyURL);
|
|
hostname = parsedProxyURL.hostname;
|
|
port = parsedProxyURL.port;
|
|
if (parsedProxyURL.protocol === 'https:') {
|
|
if (protocol === 'http') {
|
|
protocol = 'https';
|
|
}
|
|
if (!port) {
|
|
port = '443';
|
|
}
|
|
}
|
|
} else if (opts.hostType === 'localhost' || requestHostname === 'localhost') {
|
|
hostname = '127.0.0.1';
|
|
port = isPackager ? packagerInfo.packagerPort : packagerInfo.expoServerPort;
|
|
} else if (opts.hostType === 'lan' || _internal().ConnectionStatus.isOffline()) {
|
|
if (process.env.EXPO_PACKAGER_HOSTNAME) {
|
|
hostname = process.env.EXPO_PACKAGER_HOSTNAME.trim();
|
|
} else if (process.env.REACT_NATIVE_PACKAGER_HOSTNAME) {
|
|
hostname = process.env.REACT_NATIVE_PACKAGER_HOSTNAME.trim();
|
|
} else if (opts.lanType === 'ip') {
|
|
if (requestHostname) {
|
|
hostname = requestHostname;
|
|
} else {
|
|
hostname = _internal().ip.address();
|
|
}
|
|
} else {
|
|
// Some old versions of OSX work with hostname but not local ip address.
|
|
hostname = _os().default.hostname();
|
|
}
|
|
port = isPackager ? packagerInfo.packagerPort : packagerInfo.expoServerPort;
|
|
} else {
|
|
const ngrokUrl = isPackager ? packagerInfo.packagerNgrokUrl : packagerInfo.expoServerNgrokUrl;
|
|
if (!ngrokUrl || typeof ngrokUrl !== 'string') {
|
|
// TODO: if you start with --tunnel flag then this warning will always
|
|
// show up right before the tunnel starts...
|
|
_internal().ProjectUtils.logWarning(projectRoot, 'expo', 'Tunnel URL not found (it might not be ready yet), falling back to LAN URL.', 'tunnel-url-not-found');
|
|
return constructUrlAsync(projectRoot, {
|
|
...opts,
|
|
hostType: 'lan'
|
|
}, isPackager, requestHostname);
|
|
} else {
|
|
_internal().ProjectUtils.clearNotification(projectRoot, 'tunnel-url-not-found');
|
|
const pnu = _url().default.parse(ngrokUrl);
|
|
hostname = pnu.hostname;
|
|
port = pnu.port;
|
|
}
|
|
}
|
|
const url_ = joinURLComponents({
|
|
protocol,
|
|
hostname,
|
|
port
|
|
});
|
|
if (opts.urlType === 'redirect') {
|
|
return createRedirectURL(url_);
|
|
}
|
|
return url_;
|
|
}
|
|
function createRedirectURL(url) {
|
|
return `https://exp.host/--/to-exp/${encodeURIComponent(url)}`;
|
|
}
|
|
function joinURLComponents({
|
|
protocol,
|
|
hostname,
|
|
port
|
|
}) {
|
|
(0, _assert().default)(hostname, 'hostname cannot be inferred.');
|
|
// Android HMR breaks without this port 80.
|
|
// This is because Android React Native WebSocket implementation is not spec compliant and fails without a port:
|
|
// `E unknown:ReactNative: java.lang.IllegalArgumentException: Invalid URL port: "-1"`
|
|
// Invoked first in `metro-runtime/src/modules/HMRClient.js`
|
|
const validPort = port !== null && port !== void 0 ? port : '80';
|
|
const validProtocol = protocol ? `${protocol}://` : '';
|
|
return `${validProtocol}${hostname}:${validPort}`;
|
|
}
|
|
function stripJSExtension(entryPoint) {
|
|
return entryPoint.replace(/\.js$/, '');
|
|
}
|
|
function isHttps(urlString) {
|
|
return isURL(urlString, {
|
|
protocols: ['https']
|
|
});
|
|
}
|
|
function isURL(urlString, {
|
|
protocols,
|
|
requireProtocol
|
|
}) {
|
|
try {
|
|
// eslint-disable-next-line
|
|
new (_url().default.URL)(urlString);
|
|
const parsed = _url().default.parse(urlString);
|
|
if (!parsed.protocol && !requireProtocol) {
|
|
return true;
|
|
}
|
|
return protocols ? parsed.protocol ? protocols.map(x => `${x.toLowerCase()}:`).includes(parsed.protocol) : false : true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
//# sourceMappingURL=UrlUtils.js.map
|