/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow strict-local * @format * @oncall react_native */ import type {CreateCustomMessageHandlerFn} from './inspector-proxy/CustomMessageHandler'; import type {BrowserLauncher} from './types/BrowserLauncher'; import type {EventReporter} from './types/EventReporter'; import type {Experiments, ExperimentsConfig} from './types/Experiments'; import type {Logger} from './types/Logger'; import type {NextHandleFunction} from 'connect'; import InspectorProxy from './inspector-proxy/InspectorProxy'; import openDebuggerMiddleware from './middleware/openDebuggerMiddleware'; import DefaultBrowserLauncher from './utils/DefaultBrowserLauncher'; import reactNativeDebuggerFrontendPath from '@react-native/debugger-frontend'; import connect from 'connect'; import path from 'path'; import serveStaticMiddleware from 'serve-static'; type Options = $ReadOnly<{ projectRoot: string, /** * The base URL to the dev server, as addressible from the local developer * machine. This is used in responses which return URLs to other endpoints, * e.g. the debugger frontend and inspector proxy targets. * * Example: `'http://localhost:8081'`. */ serverBaseUrl: string, logger?: Logger, /** * An interface for integrators to provide a custom implementation for * opening URLs in a web browser. * * This is an unstable API with no semver guarantees. */ unstable_browserLauncher?: BrowserLauncher, /** * An interface for logging events. * * This is an unstable API with no semver guarantees. */ unstable_eventReporter?: EventReporter, /** * The set of experimental features to enable. * * This is an unstable API with no semver guarantees. */ unstable_experiments?: ExperimentsConfig, /** * Create custom handler to add support for unsupported CDP events, or debuggers. * This handler is instantiated per logical device and debugger pair. * * This is an unstable API with no semver guarantees. */ unstable_customInspectorMessageHandler?: CreateCustomMessageHandlerFn, }>; type DevMiddlewareAPI = $ReadOnly<{ middleware: NextHandleFunction, websocketEndpoints: {[path: string]: ws$WebSocketServer}, }>; export default function createDevMiddleware({ projectRoot, serverBaseUrl, logger, unstable_browserLauncher = DefaultBrowserLauncher, unstable_eventReporter, unstable_experiments: experimentConfig = {}, unstable_customInspectorMessageHandler, }: Options): DevMiddlewareAPI { const experiments = getExperiments(experimentConfig); const inspectorProxy = new InspectorProxy( projectRoot, serverBaseUrl, unstable_eventReporter, experiments, unstable_customInspectorMessageHandler, ); const middleware = connect() .use( '/open-debugger', openDebuggerMiddleware({ serverBaseUrl, inspectorProxy, browserLauncher: unstable_browserLauncher, eventReporter: unstable_eventReporter, experiments, logger, }), ) .use( '/debugger-frontend/embedder-static/embedderScript.js', (_req, res) => { res.setHeader('Content-Type', 'application/javascript'); res.end(''); }, ) .use( '/debugger-frontend', serveStaticMiddleware(path.join(reactNativeDebuggerFrontendPath), { fallthrough: false, }), ) .use((...args) => inspectorProxy.processRequest(...args)); return { middleware, websocketEndpoints: inspectorProxy.createWebSocketListeners(), }; } function getExperiments(config: ExperimentsConfig): Experiments { return { enableOpenDebuggerRedirect: config.enableOpenDebuggerRedirect ?? false, enableNetworkInspector: config.enableNetworkInspector ?? false, }; }