/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * * @format */ "use strict"; function _slicedToArray(arr, i) { return ( _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest() ); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for ( var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true ) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === "function") { ownKeys = ownKeys.concat( Object.getOwnPropertySymbols(source).filter(function(sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; }) ); } ownKeys.forEach(function(key) { _defineProperty(target, key, source[key]); }); } return target; } function _toConsumableArray(arr) { return ( _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread() ); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } function _iterableToArray(iter) { if ( Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]" ) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function() { var self = this, args = arguments; return new Promise(function(resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } const IncrementalBundler = require("./IncrementalBundler"); const MultipartResponse = require("./Server/MultipartResponse"); const baseJSBundle = require("./DeltaBundler/Serializers/baseJSBundle"); const bundleToString = require("./lib/bundle-modules/DeltaClient/bundleToString"); const deltaJSBundle = require("./DeltaBundler/Serializers/deltaJSBundle"); const getAllFiles = require("./DeltaBundler/Serializers/getAllFiles"); const getAssets = require("./DeltaBundler/Serializers/getAssets"); const getGraphId = require("./lib/getGraphId"); const getRamBundleInfo = require("./DeltaBundler/Serializers/getRamBundleInfo"); const sourceMapObject = require("./DeltaBundler/Serializers/sourceMapObject"); const sourceMapString = require("./DeltaBundler/Serializers/sourceMapString"); const splitBundleOptions = require("./lib/splitBundleOptions"); const debug = require("debug")("Metro:Server"); const formatBundlingError = require("./lib/formatBundlingError"); const mime = require("mime-types"); const parseOptionsFromUrl = require("./lib/parseOptionsFromUrl"); const transformHelpers = require("./lib/transformHelpers"); const parsePlatformFilePath = require("./node-haste/lib/parsePlatformFilePath"); const path = require("path"); const serializeDeltaJSBundle = require("./DeltaBundler/Serializers/helpers/serializeDeltaJSBundle"); const symbolicate = require("./Server/symbolicate/symbolicate"); const url = require("url"); const ResourceNotFoundError = require("./IncrementalBundler/ResourceNotFoundError"); const RevisionNotFoundError = require("./IncrementalBundler/RevisionNotFoundError"); const _require = require("./Assets"), getAsset = _require.getAsset; const _require2 = require("metro-core"), Logger = _require2.Logger, _require2$Logger = _require2.Logger, createActionStartEntry = _require2$Logger.createActionStartEntry, createActionEndEntry = _require2$Logger.createActionEndEntry, log = _require2$Logger.log; function debounceAndBatch(fn, delay) { let timeout; return () => { clearTimeout(timeout); timeout = setTimeout(fn, delay); }; } const DELTA_ID_HEADER = "X-Metro-Delta-ID"; const FILES_CHANGED_COUNT_HEADER = "X-Metro-Files-Changed-Count"; class Server { constructor(config) { var _this = this; _defineProperty(this, "processRequest", (req, res, next) => { this._processRequest(req, res, next).catch(next); }); _defineProperty( this, "_processDeltaRequest", this._createRequestProcessor({ createStartEntry(context) { return { action_name: "Requesting delta", bundle_url: context.req.url, entry_point: context.entryFile, bundler: "delta", build_id: context.buildID, bundle_options: context.bundleOptions, bundle_hash: context.graphId }; }, createEndEntry(context) { return { outdated_modules: context.result.numModifiedFiles }; }, build: (function() { var _ref = _asyncToGenerator(function*(_ref2) { let revisionId = _ref2.revisionId, graphId = _ref2.graphId, entryFile = _ref2.entryFile, transformOptions = _ref2.transformOptions, serializerOptions = _ref2.serializerOptions, onProgress = _ref2.onProgress; // TODO(T34760593): We should eventually move to a model where this // endpoint is placed at /delta/:revisionId, and requesting an unknown revisionId // throws a 404. // However, this would break existing delta clients, since they expect the // endpoint to rebuild the graph, were it not found in cache. let revPromise; if (revisionId != null) { revPromise = _this._bundler.getRevision(revisionId); } // Even if we receive a revisionId, it might have expired. if (revPromise == null) { revPromise = _this._bundler.getRevisionByGraphId(graphId); } let delta; let revision; if (revPromise != null) { const prevRevision = yield revPromise; var _ref3 = yield _this._bundler.updateGraph( prevRevision, prevRevision.id !== revisionId ); delta = _ref3.delta; revision = _ref3.revision; } else { var _ref4 = yield _this._bundler.initializeGraph( entryFile, transformOptions, { onProgress } ); delta = _ref4.delta; revision = _ref4.revision; } const bundle = deltaJSBundle( entryFile, revision.prepend, delta, revision.id, revision.graph, { processModuleFilter: _this._config.serializer.processModuleFilter, createModuleId: _this._createModuleId, dev: transformOptions.dev, getRunModuleStatement: _this._config.serializer.getRunModuleStatement, projectRoot: _this._config.projectRoot, runBeforeMainModule: _this._config.serializer.getModulesRunBeforeMainModule( path.relative(_this._config.projectRoot, entryFile) ), runModule: serializerOptions.runModule, sourceMapUrl: serializerOptions.sourceMapUrl, inlineSourceMap: serializerOptions.inlineSourceMap } ); return { numModifiedFiles: delta.added.size + delta.modified.size + delta.deleted.size, nextRevId: revision.id, bundle }; }); return function build(_x) { return _ref.apply(this, arguments); }; })(), finish(_ref5) { let mres = _ref5.mres, result = _ref5.result; const bundle = serializeDeltaJSBundle.toJSON(result.bundle); mres.setHeader( FILES_CHANGED_COUNT_HEADER, String(result.numModifiedFiles) ); mres.setHeader(DELTA_ID_HEADER, String(result.nextRevId)); mres.setHeader("Content-Type", "application/json"); mres.setHeader("Content-Length", String(Buffer.byteLength(bundle))); mres.end(bundle); } }) ); _defineProperty( this, "_processBundleRequest", this._createRequestProcessor({ createStartEntry(context) { return { action_name: "Requesting bundle", bundle_url: context.req.url, entry_point: context.entryFile, bundler: "delta", build_id: context.buildID, bundle_options: context.bundleOptions, bundle_hash: context.graphId }; }, createEndEntry(context) { return { outdated_modules: context.result.numModifiedFiles }; }, build: (function() { var _ref6 = _asyncToGenerator(function*(_ref7) { let graphId = _ref7.graphId, entryFile = _ref7.entryFile, transformOptions = _ref7.transformOptions, serializerOptions = _ref7.serializerOptions, onProgress = _ref7.onProgress; const revPromise = _this._bundler.getRevisionByGraphId(graphId); const _ref8 = yield revPromise != null ? _this._bundler.updateGraph(yield revPromise, false) : _this._bundler.initializeGraph(entryFile, transformOptions, { onProgress }), delta = _ref8.delta, revision = _ref8.revision; const serializer = _this._config.serializer.customSerializer || function() { return bundleToString(baseJSBundle.apply(void 0, arguments)) .code; }; const bundle = serializer( entryFile, revision.prepend, revision.graph, { processModuleFilter: _this._config.serializer.processModuleFilter, createModuleId: _this._createModuleId, getRunModuleStatement: _this._config.serializer.getRunModuleStatement, dev: transformOptions.dev, projectRoot: _this._config.projectRoot, runBeforeMainModule: _this._config.serializer.getModulesRunBeforeMainModule( path.relative(_this._config.projectRoot, entryFile) ), runModule: serializerOptions.runModule, sourceMapUrl: serializerOptions.sourceMapUrl, inlineSourceMap: serializerOptions.inlineSourceMap } ); return { numModifiedFiles: delta.reset ? delta.added.size + revision.prepend.length : delta.added.size + delta.modified.size + delta.deleted.size, lastModifiedDate: revision.date, nextRevId: revision.id, bundle }; }); return function build(_x2) { return _ref6.apply(this, arguments); }; })(), finish(_ref9) { let req = _ref9.req, mres = _ref9.mres, result = _ref9.result; if ( // We avoid parsing the dates since the client should never send a more // recent date than the one returned by the Delta Bundler (if that's the // case it's fine to return the whole bundle). req.headers["if-modified-since"] === result.lastModifiedDate.toUTCString() ) { debug("Responding with 304"); mres.writeHead(304); mres.end(); } else { mres.setHeader( FILES_CHANGED_COUNT_HEADER, String(result.numModifiedFiles) ); mres.setHeader(DELTA_ID_HEADER, String(result.nextRevId)); mres.setHeader("Content-Type", "application/javascript"); mres.setHeader( "Last-Modified", result.lastModifiedDate.toUTCString() ); mres.setHeader( "Content-Length", String(Buffer.byteLength(result.bundle)) ); mres.end(result.bundle); } } }) ); _defineProperty( this, "_processSourceMapRequest", this._createRequestProcessor({ createStartEntry(context) { return { action_name: "Requesting sourcemap", bundle_url: context.req.url, entry_point: context.entryFile, bundler: "delta" }; }, createEndEntry(context) { return { bundler: "delta" }; }, build: (function() { var _ref10 = _asyncToGenerator(function*(_ref11) { let entryFile = _ref11.entryFile, transformOptions = _ref11.transformOptions, serializerOptions = _ref11.serializerOptions, onProgress = _ref11.onProgress, graphId = _ref11.graphId; let revision; const revPromise = _this._bundler.getRevisionByGraphId(graphId); if (revPromise == null) { var _ref12 = yield _this._bundler.initializeGraph( entryFile, transformOptions, { onProgress } ); revision = _ref12.revision; } else { revision = yield revPromise; } const _revision = revision, prepend = _revision.prepend, graph = _revision.graph; return sourceMapString( _toConsumableArray(prepend).concat( _toConsumableArray(_this._getSortedModules(graph)) ), { excludeSource: serializerOptions.excludeSource, processModuleFilter: _this._config.serializer.processModuleFilter } ); }); return function build(_x3) { return _ref10.apply(this, arguments); }; })(), finish(_ref13) { let mres = _ref13.mres, result = _ref13.result; mres.setHeader("Content-Type", "application/json"); mres.end(result.toString()); } }) ); _defineProperty( this, "_processMetadataRequest", this._createRequestProcessor({ createStartEntry(context) { return { action_name: "Requesting bundle metadata", bundle_url: context.req.url, entry_point: context.entryFile, bundler: "delta" }; }, createEndEntry(context) { return { bundler: "delta" }; }, build: (function() { var _ref14 = _asyncToGenerator(function*(_ref15) { let entryFile = _ref15.entryFile, transformOptions = _ref15.transformOptions, serializerOptions = _ref15.serializerOptions, onProgress = _ref15.onProgress, revisionId = _ref15.revisionId; if (revisionId == null) { throw new Error( "You must provide a `revisionId` query parameter to the metadata endpoint." ); } let revision; const revPromise = _this._bundler.getRevision(revisionId); if (revPromise == null) { throw new RevisionNotFoundError(revisionId); } else { revision = yield revPromise; } const base = baseJSBundle( entryFile, revision.prepend, revision.graph, { processModuleFilter: _this._config.serializer.processModuleFilter, createModuleId: _this._createModuleId, getRunModuleStatement: _this._config.serializer.getRunModuleStatement, dev: transformOptions.dev, projectRoot: _this._config.projectRoot, runBeforeMainModule: _this._config.serializer.getModulesRunBeforeMainModule( path.relative(_this._config.projectRoot, entryFile) ), runModule: serializerOptions.runModule, sourceMapUrl: serializerOptions.sourceMapUrl, inlineSourceMap: serializerOptions.inlineSourceMap } ); return bundleToString(base).metadata; }); return function build(_x4) { return _ref14.apply(this, arguments); }; })(), finish(_ref16) { let mres = _ref16.mres, result = _ref16.result; mres.setHeader("Content-Type", "application/json"); mres.end(JSON.stringify(result)); } }) ); _defineProperty( this, "_processAssetsRequest", this._createRequestProcessor({ createStartEntry(context) { return { action_name: "Requesting assets", bundle_url: context.req.url, entry_point: context.entryFile, bundler: "delta" }; }, createEndEntry(context) { return { bundler: "delta" }; }, build: (function() { var _ref17 = _asyncToGenerator(function*(_ref18) { let entryFile = _ref18.entryFile, transformOptions = _ref18.transformOptions, onProgress = _ref18.onProgress; const _ref19 = yield _this._bundler.buildGraph( entryFile, transformOptions, { onProgress } ), graph = _ref19.graph; return yield getAssets(graph, { processModuleFilter: _this._config.serializer.processModuleFilter, assetPlugins: _this._config.transformer.assetPlugins, platform: transformOptions.platform, publicPath: _this._config.transformer.publicPath, projectRoot: _this._config.projectRoot }); }); return function build(_x5) { return _ref17.apply(this, arguments); }; })(), finish(_ref20) { let mres = _ref20.mres, result = _ref20.result; mres.setHeader("Content-Type", "application/json"); mres.end(JSON.stringify(result)); } }) ); this._config = config; if (this._config.resetCache) { this._config.cacheStores.forEach(store => store.clear()); this._config.reporter.update({ type: "transform_cache_reset" }); } this._reporter = config.reporter; this._logger = Logger; this._changeWatchers = []; this._platforms = new Set(this._config.resolver.platforms); // TODO(T34760917): These two properties should eventually be instantiated // elsewhere and passed as parameters, since they are also needed by // the HmrServer. // The whole bundling/serializing logic should follow as well. this._createModuleId = config.serializer.createModuleIdFactory(); this._bundler = new IncrementalBundler(config); const debouncedFileChangeHandler = debounceAndBatch( () => this._informChangeWatchers(), 50 ); // changes to the haste map can affect resolution of files in the bundle this._bundler .getBundler() .getDependencyGraph() .then(dependencyGraph => { dependencyGraph.getWatcher().on("change", () => { // Make sure the file watcher event runs through the system before // we rebuild the bundles. debouncedFileChangeHandler(); }); }); this._symbolicateInWorker = symbolicate.createWorker(); this._nextBundleBuildID = 1; } end() { this._bundler.end(); } getBundler() { return this._bundler; } getCreateModuleId() { return this._createModuleId; } build(options) { var _this2 = this; return _asyncToGenerator(function*() { const _splitBundleOptions = splitBundleOptions(options), entryFile = _splitBundleOptions.entryFile, transformOptions = _splitBundleOptions.transformOptions, serializerOptions = _splitBundleOptions.serializerOptions, onProgress = _splitBundleOptions.onProgress; const _ref21 = yield _this2._bundler.buildGraph( entryFile, transformOptions, { onProgress } ), prepend = _ref21.prepend, graph = _ref21.graph; const entryPoint = path.resolve(_this2._config.projectRoot, entryFile); const bundle = baseJSBundle(entryPoint, prepend, graph, { processModuleFilter: _this2._config.serializer.processModuleFilter, createModuleId: _this2._createModuleId, getRunModuleStatement: _this2._config.serializer.getRunModuleStatement, dev: transformOptions.dev, projectRoot: _this2._config.projectRoot, runBeforeMainModule: _this2._config.serializer.getModulesRunBeforeMainModule( path.relative(_this2._config.projectRoot, entryPoint) ), runModule: serializerOptions.runModule, sourceMapUrl: serializerOptions.sourceMapUrl, inlineSourceMap: serializerOptions.inlineSourceMap }); return { code: bundleToString(bundle).code, map: sourceMapString( _toConsumableArray(prepend).concat( _toConsumableArray(_this2._getSortedModules(graph)) ), { excludeSource: serializerOptions.excludeSource, processModuleFilter: _this2._config.serializer.processModuleFilter } ) }; })(); } getRamBundleInfo(options) { var _this3 = this; return _asyncToGenerator(function*() { const _splitBundleOptions2 = splitBundleOptions(options), entryFile = _splitBundleOptions2.entryFile, transformOptions = _splitBundleOptions2.transformOptions, serializerOptions = _splitBundleOptions2.serializerOptions, onProgress = _splitBundleOptions2.onProgress; const _ref22 = yield _this3._bundler.buildGraph( entryFile, transformOptions, { onProgress } ), prepend = _ref22.prepend, graph = _ref22.graph; const entryPoint = path.resolve(_this3._config.projectRoot, entryFile); return yield getRamBundleInfo(entryPoint, prepend, graph, { processModuleFilter: _this3._config.serializer.processModuleFilter, createModuleId: _this3._createModuleId, dev: transformOptions.dev, excludeSource: serializerOptions.excludeSource, getRunModuleStatement: _this3._config.serializer.getRunModuleStatement, getTransformOptions: _this3._config.transformer.getTransformOptions, platform: transformOptions.platform, projectRoot: _this3._config.projectRoot, runBeforeMainModule: _this3._config.serializer.getModulesRunBeforeMainModule( path.relative(_this3._config.projectRoot, entryPoint) ), runModule: serializerOptions.runModule, sourceMapUrl: serializerOptions.sourceMapUrl, inlineSourceMap: serializerOptions.inlineSourceMap }); })(); } getAssets(options) { var _this4 = this; return _asyncToGenerator(function*() { const _splitBundleOptions3 = splitBundleOptions(options), entryFile = _splitBundleOptions3.entryFile, transformOptions = _splitBundleOptions3.transformOptions, onProgress = _splitBundleOptions3.onProgress; const _ref23 = yield _this4._bundler.buildGraph( entryFile, transformOptions, { onProgress } ), graph = _ref23.graph; return yield getAssets(graph, { processModuleFilter: _this4._config.serializer.processModuleFilter, assetPlugins: _this4._config.transformer.assetPlugins, platform: transformOptions.platform, projectRoot: _this4._config.projectRoot, publicPath: _this4._config.transformer.publicPath }); })(); } getOrderedDependencyPaths(options) { var _this5 = this; return _asyncToGenerator(function*() { const _splitBundleOptions4 = splitBundleOptions( _objectSpread({}, Server.DEFAULT_BUNDLE_OPTIONS, options, { bundleType: "bundle" }) ), entryFile = _splitBundleOptions4.entryFile, transformOptions = _splitBundleOptions4.transformOptions, onProgress = _splitBundleOptions4.onProgress; const _ref24 = yield _this5._bundler.buildGraph( entryFile, transformOptions, { onProgress } ), prepend = _ref24.prepend, graph = _ref24.graph; const platform = transformOptions.platform || parsePlatformFilePath(entryFile, _this5._platforms).platform; return yield getAllFiles(prepend, graph, { platform, processModuleFilter: _this5._config.serializer.processModuleFilter }); })(); } _informChangeWatchers() { const watchers = this._changeWatchers; const headers = { "Content-Type": "application/json; charset=UTF-8" }; watchers.forEach(function(w) { w.res.writeHead(205, headers); w.res.end( JSON.stringify({ changed: true }) ); }); this._changeWatchers = []; } _processOnChangeRequest(req, res) { const watchers = this._changeWatchers; watchers.push({ req, res }); req.on("close", () => { for (let i = 0; i < watchers.length; i++) { if (watchers[i] && watchers[i].req === req) { watchers.splice(i, 1); break; } } }); } _rangeRequestMiddleware(req, res, data, assetPath) { if (req.headers && req.headers.range) { const _req$headers$range$re = req.headers.range .replace(/bytes=/, "") .split("-"), _req$headers$range$re2 = _slicedToArray(_req$headers$range$re, 2), rangeStart = _req$headers$range$re2[0], rangeEnd = _req$headers$range$re2[1]; const dataStart = parseInt(rangeStart, 10); const dataEnd = rangeEnd ? parseInt(rangeEnd, 10) : data.length - 1; const chunksize = dataEnd - dataStart + 1; res.writeHead(206, { "Accept-Ranges": "bytes", "Content-Length": chunksize.toString(), "Content-Range": `bytes ${dataStart}-${dataEnd}/${data.length}`, "Content-Type": mime.lookup(path.basename(assetPath[1])) }); return data.slice(dataStart, dataEnd + 1); } return data; } _processSingleAssetRequest(req, res) { var _this6 = this; return _asyncToGenerator(function*() { const urlObj = url.parse(decodeURI(req.url), true); /* $FlowFixMe: could be empty if the url is invalid */ const assetPath = urlObj.pathname.match(/^\/assets\/(.+)$/); const processingAssetRequestLogEntry = log( createActionStartEntry({ action_name: "Processing asset request", asset: assetPath[1] }) ); try { const data = yield getAsset( assetPath[1], _this6._config.projectRoot, _this6._config.watchFolders, /* $FlowFixMe: query may be empty for invalid URLs */ urlObj.query.platform ); // Tell clients to cache this for 1 year. // This is safe as the asset url contains a hash of the asset. if (process.env.REACT_NATIVE_ENABLE_ASSET_CACHING === true) { res.setHeader("Cache-Control", "max-age=31536000"); } res.end(_this6._rangeRequestMiddleware(req, res, data, assetPath)); process.nextTick(() => { log(createActionEndEntry(processingAssetRequestLogEntry)); }); } catch (error) { console.error(error.stack); res.writeHead(404); res.end("Asset not found"); } })(); } _processRequest(req, res, next) { var _this7 = this; return _asyncToGenerator(function*() { const urlObj = url.parse(req.url, true); const host = req.headers.host; debug(`Handling request: ${host ? "http://" + host : ""}${req.url}`); /* $FlowFixMe: Could be empty if the URL is invalid. */ const pathname = urlObj.pathname; if (pathname.match(/\.bundle$/)) { yield _this7._processBundleRequest(req, res); } else if (pathname.match(/\.map$/)) { yield _this7._processSourceMapRequest(req, res); } else if (pathname.match(/\.assets$/)) { yield _this7._processAssetsRequest(req, res); } else if (pathname.match(/\.delta$/)) { yield _this7._processDeltaRequest(req, res); } else if (pathname.match(/\.meta/)) { yield _this7._processMetadataRequest(req, res); } else if (pathname.match(/^\/onchange\/?$/)) { _this7._processOnChangeRequest(req, res); } else if (pathname.match(/^\/assets\//)) { yield _this7._processSingleAssetRequest(req, res); } else if (pathname === "/symbolicate") { _this7._symbolicate(req, res); } else { next(); } })(); } _createRequestProcessor(_ref25) { let createStartEntry = _ref25.createStartEntry, createEndEntry = _ref25.createEndEntry, build = _ref25.build, finish = _ref25.finish; return ( /*#__PURE__*/ (function() { var _requestProcessor = _asyncToGenerator(function*(req, res) { const mres = MultipartResponse.wrap(req, res); const _parseOptionsFromUrl = parseOptionsFromUrl( url.format( _objectSpread({}, url.parse(req.url), { protocol: "http", host: req.headers.host }) ), new Set(this._config.resolver.platforms) ), revisionId = _parseOptionsFromUrl.revisionId, bundleOptions = _parseOptionsFromUrl.options; const _splitBundleOptions5 = splitBundleOptions(bundleOptions), entryFile = _splitBundleOptions5.entryFile, transformOptions = _splitBundleOptions5.transformOptions, serializerOptions = _splitBundleOptions5.serializerOptions; /** * `entryFile` is relative to projectRoot, we need to use resolution function * to find the appropriate file with supported extensions. */ const resolutionFn = yield transformHelpers.getResolveDependencyFn( this._bundler.getBundler(), transformOptions.platform ); const resolvedEntryFilePath = resolutionFn( `${this._config.projectRoot}/.`, entryFile ); const graphId = getGraphId(resolvedEntryFilePath, transformOptions); const buildID = this.getNewBuildID(); let onProgress = null; if (this._config.reporter) { onProgress = (transformedFileCount, totalFileCount) => { mres.writeChunk( { "Content-Type": "application/json" }, JSON.stringify({ done: transformedFileCount, total: totalFileCount }) ); this._reporter.update({ buildID, type: "bundle_transform_progressed", transformedFileCount, totalFileCount }); }; } /* $FlowFixMe(>=0.63.0 site=react_native_fb) This comment suppresses an * error found when Flow v0.63 was deployed. To see the error delete this * comment and run Flow. */ this._reporter.update({ buildID, bundleDetails: { entryFile: resolvedEntryFilePath, platform: transformOptions.platform, dev: transformOptions.dev, minify: transformOptions.minify, bundleType: bundleOptions.bundleType }, type: "bundle_build_started" }); const startContext = { req, mres, revisionId, buildID, bundleOptions, entryFile: resolvedEntryFilePath, transformOptions, serializerOptions, onProgress, graphId }; const logEntry = log( createActionStartEntry(createStartEntry(startContext)) ); let result; try { result = yield build(startContext); } catch (error) { const formattedError = formatBundlingError(error); const status = error instanceof ResourceNotFoundError ? 404 : 500; mres.writeHead(status, { "Content-Type": "application/json; charset=UTF-8" }); mres.end(JSON.stringify(formattedError)); this._reporter.update({ error, type: "bundling_error" }); log({ action_name: "bundling_error", error_type: formattedError.type, log_entry_label: "bundling_error", bundle_id: graphId, build_id: buildID, stack: formattedError.message }); this._reporter.update({ buildID, type: "bundle_build_failed", bundleOptions }); return; } const endContext = _objectSpread({}, startContext, { result }); finish(endContext); this._reporter.update({ buildID, type: "bundle_build_done" }); log( createActionEndEntry( _objectSpread({}, logEntry, createEndEntry(endContext)) ) ); }); return function requestProcessor(_x6, _x7) { return _requestProcessor.apply(this, arguments); }; })() ); } // This function ensures that modules in source maps are sorted in the same // order as in a plain JS bundle. _getSortedModules(graph) { return _toConsumableArray(graph.dependencies.values()).sort( (a, b) => this._createModuleId(a.path) - this._createModuleId(b.path) ); } _symbolicate(req, res) { const symbolicatingLogEntry = log(createActionStartEntry("Symbolicating")); debug("Start symbolication"); /* $FlowFixMe: where is `rowBody` defined? Is it added by * the `connect` framework? */ Promise.resolve(req.rawBody) .then(body => { const stack = JSON.parse(body).stack; // In case of multiple bundles / HMR, some stack frames can have // different URLs from others const urls = new Set(); stack.forEach(frame => { const sourceUrl = frame.file; // Skip `/debuggerWorker.js` which drives remote debugging because it // does not need to symbolication. // Skip anything except http(s), because there is no support for that yet if ( sourceUrl != null && !urls.has(sourceUrl) && !sourceUrl.endsWith("/debuggerWorker.js") && sourceUrl.startsWith("http") ) { urls.add(sourceUrl); } }); const mapPromises = Array.from(urls.values()).map( this._sourceMapForURL, this ); debug("Getting source maps for symbolication"); return Promise.all(mapPromises).then(maps => { debug("Sending stacks and maps to symbolication worker"); const urlsToMaps = zip(urls.values(), maps); return this._symbolicateInWorker(stack, urlsToMaps); }); }) .then( stack => { debug("Symbolication done"); res.end( JSON.stringify({ stack }) ); process.nextTick(() => { log(createActionEndEntry(symbolicatingLogEntry)); }); }, error => { console.error(error.stack || error); res.statusCode = 500; res.end( JSON.stringify({ error: error.message }) ); } ); } _sourceMapForURL(reqUrl) { var _this8 = this; return _asyncToGenerator(function*() { const _parseOptionsFromUrl2 = parseOptionsFromUrl( reqUrl, new Set(_this8._config.resolver.platforms) ), options = _parseOptionsFromUrl2.options; const _splitBundleOptions6 = splitBundleOptions(options), entryFile = _splitBundleOptions6.entryFile, transformOptions = _splitBundleOptions6.transformOptions, serializerOptions = _splitBundleOptions6.serializerOptions, onProgress = _splitBundleOptions6.onProgress; /** * `entryFile` is relative to projectRoot, we need to use resolution function * to find the appropriate file with supported extensions. */ const resolutionFn = yield transformHelpers.getResolveDependencyFn( _this8._bundler.getBundler(), transformOptions.platform ); const resolvedEntryFilePath = resolutionFn( `${_this8._config.projectRoot}/.`, entryFile ); const graphId = getGraphId(resolvedEntryFilePath, transformOptions); let revision; const revPromise = _this8._bundler.getRevisionByGraphId(graphId); if (revPromise == null) { var _ref26 = yield _this8._bundler.initializeGraph( resolvedEntryFilePath, transformOptions, { onProgress } ); revision = _ref26.revision; } else { revision = yield revPromise; } const _revision2 = revision, prepend = _revision2.prepend, graph = _revision2.graph; return sourceMapObject( _toConsumableArray(prepend).concat( _toConsumableArray(_this8._getSortedModules(graph)) ), { excludeSource: serializerOptions.excludeSource, processModuleFilter: _this8._config.serializer.processModuleFilter } ); })(); } getNewBuildID() { return (this._nextBundleBuildID++).toString(36); } getPlatforms() { return this._config.resolver.platforms; } getWatchFolders() { return this._config.watchFolders; } getVisualizerConfig() { return this._config.visualizer; } } _defineProperty(Server, "DEFAULT_GRAPH_OPTIONS", { customTransformOptions: Object.create(null), dev: true, hot: false, minify: false }); _defineProperty( Server, "DEFAULT_BUNDLE_OPTIONS", _objectSpread({}, Server.DEFAULT_GRAPH_OPTIONS, { excludeSource: false, inlineSourceMap: false, onProgress: null, runModule: true, sourceMapUrl: null }) ); function* zip(xs, ys) { //$FlowIssue #9324959 const ysIter = ys[Symbol.iterator](); for (const x of xs) { const y = ysIter.next(); if (y.done) { return; } yield [x, y.value]; } } module.exports = Server;