first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = void 0;
var _util = require("util");
class OpenDebuggerKeyboardHandler {
#devServerUrl;
#reporter;
#targetsShownForSelection = null;
constructor({ devServerUrl, reporter }) {
this.#devServerUrl = devServerUrl;
this.#reporter = reporter;
}
async #tryOpenDebuggerForTarget(target) {
this.#targetsShownForSelection = null;
this.#clearTerminalMenu();
try {
await fetch(
new URL(
"/open-debugger?target=" + encodeURIComponent(target.id),
this.#devServerUrl,
).href,
{
method: "POST",
},
);
} catch (e) {
this.#log(
"error",
"Failed to open debugger for %s (%s): %s",
target.title,
target.description,
"Network error",
);
if (e.cause != null) {
this.#log("error", "Cause: %s", e.cause);
}
this.#clearTerminalMenu();
}
}
async handleOpenDebugger() {
this.#setTerminalMenu("Fetching available debugging targets...");
this.#targetsShownForSelection = null;
try {
const res = await fetch(this.#devServerUrl + "/json/list", {
method: "POST",
});
if (res.status !== 200) {
throw new Error(`Unexpected status code: ${res.status}`);
}
const targets = await res.json();
if (!Array.isArray(targets)) {
throw new Error("Expected array.");
}
if (targets.length === 0) {
this.#log("warn", "No connected targets");
this.#clearTerminalMenu();
} else if (targets.length === 1) {
const target = targets[0];
void this.#tryOpenDebuggerForTarget(target);
} else {
this.#targetsShownForSelection = targets;
if (targets.length > 9) {
this.#log(
"warn",
"10 or more debug targets available, showing the first 9.",
);
}
this.#setTerminalMenu(
`Multiple debug targets available, please select:\n ${targets
.slice(0, 9)
.map(
({ title }, i) =>
`${(0, _util.styleText)(["white", "inverse"], ` ${i + 1} `)} - "${title}"`,
)
.join("\n ")}`,
);
}
} catch (e) {
this.#log("error", `Failed to fetch debug targets: ${e.message}`);
this.#clearTerminalMenu();
}
}
maybeHandleTargetSelection(keyName) {
if (keyName >= "1" && keyName <= "9") {
const targetIndex = Number(keyName) - 1;
if (
this.#targetsShownForSelection != null &&
targetIndex < this.#targetsShownForSelection.length
) {
const target = this.#targetsShownForSelection[targetIndex];
void this.#tryOpenDebuggerForTarget(target);
return true;
}
}
return false;
}
dismiss() {
this.#clearTerminalMenu();
this.#targetsShownForSelection = null;
}
#log(level, ...data) {
this.#reporter.update({
type: "unstable_server_log",
level,
data,
});
}
#setTerminalMenu(message) {
this.#reporter.update({
type: "unstable_server_menu_updated",
message,
});
}
#clearTerminalMenu() {
this.#reporter.update({
type: "unstable_server_menu_cleared",
});
}
}
exports.default = OpenDebuggerKeyboardHandler;

View File

@@ -0,0 +1,39 @@
/**
* 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
*/
import type { TerminalReporter } from "metro";
declare export default class OpenDebuggerKeyboardHandler {
constructor($$PARAM_0$$: {
devServerUrl: string,
reporter: TerminalReporter,
}): void;
/**
* Used in response to 'j' to debug - fetch the available debug targets and:
* - If no targets, warn
* - If one target, open it
* - If more, show a list. The keyboard listener should run subsequent key
* presses through maybeHandleTargetSelection, which will launch the
* debugger if a match is made.
*/
handleOpenDebugger(): Promise<void>;
/**
* Handle key presses that correspond to a valid selection from a visible
* selection list.
*
* @return true if we've handled the key as a target selection, false if the
* caller should handle the key.
*/
maybeHandleTargetSelection(keyName: string): boolean;
/**
* Dismiss any target selection UI, if shown.
*/
dismiss(): void;
}

View File

@@ -0,0 +1,103 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = attachKeyHandlers;
var _OpenDebuggerKeyboardHandler = _interopRequireDefault(
require("./OpenDebuggerKeyboardHandler"),
);
var _invariant = _interopRequireDefault(require("invariant"));
var _readline = _interopRequireDefault(require("readline"));
var _tty = require("tty");
var _util = require("util");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
const CTRL_C = "\u0003";
const CTRL_D = "\u0004";
const RELOAD_TIMEOUT = 500;
const throttle = (callback, timeout) => {
let previousCallTimestamp = 0;
return () => {
const currentCallTimestamp = new Date().getTime();
if (currentCallTimestamp - previousCallTimestamp > timeout) {
previousCallTimestamp = currentCallTimestamp;
callback();
}
};
};
function attachKeyHandlers({ devServerUrl, messageSocket, reporter }) {
if (process.stdin.isTTY !== true) {
reporter.update({
type: "unstable_server_log",
level: "info",
data: "Interactive mode is not supported in this environment",
});
return;
}
_readline.default.emitKeypressEvents(process.stdin);
setRawMode(true);
const reload = throttle(() => {
reporter.update({
type: "unstable_server_log",
level: "info",
data: "Reloading connected app(s)...",
});
messageSocket.broadcast("reload", null);
}, RELOAD_TIMEOUT);
const openDebuggerKeyboardHandler = new _OpenDebuggerKeyboardHandler.default({
reporter,
devServerUrl,
});
process.stdin.on("keypress", (str, key) => {
if (openDebuggerKeyboardHandler.maybeHandleTargetSelection(key.name)) {
return;
}
switch (key.sequence) {
case "r":
reload();
break;
case "d":
reporter.update({
type: "unstable_server_log",
level: "info",
data: "Opening Dev Menu...",
});
messageSocket.broadcast("devMenu", null);
break;
case "j":
void openDebuggerKeyboardHandler.handleOpenDebugger();
break;
case CTRL_C:
case CTRL_D:
openDebuggerKeyboardHandler.dismiss();
reporter.update({
type: "unstable_server_log",
level: "info",
data: "Stopping server",
});
setRawMode(false);
process.stdin.pause();
process.emit("SIGINT");
process.exit();
}
});
reporter.update({
type: "unstable_server_log",
level: "info",
data: `Key commands available:
${(0, _util.styleText)(["bold", "inverse"], " r ")} - reload app(s)
${(0, _util.styleText)(["bold", "inverse"], " d ")} - open Dev Menu
${(0, _util.styleText)(["bold", "inverse"], " j ")} - open DevTools
`,
});
}
function setRawMode(enable) {
(0, _invariant.default)(
process.stdin instanceof _tty.ReadStream,
"process.stdin must be a readable stream to modify raw mode",
);
process.stdin.setRawMode(enable);
}

View File

@@ -0,0 +1,20 @@
/**
* 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
*/
import type { TerminalReporter } from "metro";
declare export default function attachKeyHandlers($$PARAM_0$$: {
devServerUrl: string,
messageSocket: $ReadOnly<{
broadcast: (type: string, params?: Record<string, mixed> | null) => void,
...
}>,
reporter: TerminalReporter,
}): void;

View File

@@ -0,0 +1,101 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = void 0;
var _runServer = _interopRequireDefault(require("./runServer"));
var _path = _interopRequireDefault(require("path"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
const startCommand = {
name: "start",
func: _runServer.default,
description: "Start the React Native development server.",
options: [
{
name: "--port <number>",
parse: Number,
},
{
name: "--host <string>",
default: "",
},
{
name: "--projectRoot <path>",
description: "Path to a custom project root",
parse: (val) => _path.default.resolve(val),
},
{
name: "--watchFolders <list>",
description:
"Specify any additional folders to be added to the watch list",
parse: (val) =>
val.split(",").map((folder) => _path.default.resolve(folder)),
},
{
name: "--assetPlugins <list>",
description:
"Specify any additional asset plugins to be used by the packager by full filepath",
parse: (val) => val.split(","),
},
{
name: "--sourceExts <list>",
description:
"Specify any additional source extensions to be used by the packager",
parse: (val) => val.split(","),
},
{
name: "--max-workers <number>",
description:
"Specifies the maximum number of workers the worker-pool " +
"will spawn for transforming files. This defaults to the number of the " +
"cores available on your machine.",
parse: (workers) => Number(workers),
},
{
name: "--transformer <string>",
description: "Specify a custom transformer to be used",
},
{
name: "--reset-cache, --resetCache",
description: "Removes cached files",
},
{
name: "--custom-log-reporter-path, --customLogReporterPath <string>",
description:
"Path to a JavaScript file that exports a log reporter as a replacement for TerminalReporter",
},
{
name: "--https",
description: "Enables https connections to the server",
},
{
name: "--key <path>",
description: "Path to custom SSL key",
},
{
name: "--cert <path>",
description: "Path to custom SSL cert",
},
{
name: "--config <string>",
description: "Path to the CLI configuration file",
parse: (val) => _path.default.resolve(val),
},
{
name: "--no-interactive",
description: "Disables interactive mode",
},
{
name: "--client-logs",
description:
"[Deprecated] Enable plain text JavaScript log streaming for all " +
"connected apps. This feature is deprecated and will be removed in " +
"future.",
default: false,
},
],
};
var _default = (exports.default = startCommand);

View File

@@ -0,0 +1,17 @@
/**
* 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
*/
import type { Command } from "@react-native-community/cli-types";
export type { StartCommandArgs } from "./runServer";
declare const startCommand: Command;
declare export default typeof startCommand;

View File

@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.createDevServerMiddleware = void 0;
const debug = require("debug")("ReactNative:CommunityCliPlugin");
const unusedStubWSServer = {};
const unusedMiddlewareStub = {};
const communityMiddlewareFallback = {
createDevServerMiddleware: (params) => ({
middleware: unusedMiddlewareStub,
websocketEndpoints: {},
messageSocketEndpoint: {
server: unusedStubWSServer,
broadcast: (method, _params) => {},
},
eventsSocketEndpoint: {
server: unusedStubWSServer,
reportEvent: (event) => {},
},
}),
};
try {
const communityCliPath = require.resolve("@react-native-community/cli");
const communityCliServerApiPath = require.resolve(
"@react-native-community/cli-server-api",
{
paths: [communityCliPath],
},
);
communityMiddlewareFallback.createDevServerMiddleware = require(
communityCliServerApiPath,
).createDevServerMiddleware;
} catch {
debug(`⚠️ Unable to find @react-native-community/cli-server-api
Starting the server without the community middleware.`);
}
const createDevServerMiddleware = (exports.createDevServerMiddleware =
communityMiddlewareFallback.createDevServerMiddleware);

View File

@@ -0,0 +1,38 @@
/**
* 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
*/
import type { Server } from "connect";
import type { TerminalReportableEvent } from "metro";
type MiddlewareReturn = {
middleware: Server,
websocketEndpoints: {
[path: string]: ws$WebSocketServer,
},
messageSocketEndpoint: {
server: ws$WebSocketServer,
broadcast: (method: string, params?: Record<string, mixed> | null) => void,
},
eventsSocketEndpoint: {
server: ws$WebSocketServer,
reportEvent: (event: TerminalReportableEvent) => void,
},
...
};
declare const communityMiddlewareFallback: {
createDevServerMiddleware: (params: {
host?: string,
port: number,
watchFolders: $ReadOnlyArray<string>,
}) => MiddlewareReturn,
};
declare export const createDevServerMiddleware: typeof communityMiddlewareFallback.createDevServerMiddleware;

View File

@@ -0,0 +1,174 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = void 0;
var _createDevMiddlewareLogger = _interopRequireDefault(
require("../../utils/createDevMiddlewareLogger"),
);
var _isDevServerRunning = _interopRequireDefault(
require("../../utils/isDevServerRunning"),
);
var _loadMetroConfig = _interopRequireDefault(
require("../../utils/loadMetroConfig"),
);
var version = _interopRequireWildcard(require("../../utils/version"));
var _attachKeyHandlers = _interopRequireDefault(require("./attachKeyHandlers"));
var _middleware = require("./middleware");
var _devMiddleware = require("@react-native/dev-middleware");
var _metro = _interopRequireDefault(require("metro"));
var _metroCore = require("metro-core");
var _path = _interopRequireDefault(require("path"));
var _url = _interopRequireDefault(require("url"));
var _util = require("util");
function _interopRequireWildcard(e, t) {
if ("function" == typeof WeakMap)
var r = new WeakMap(),
n = new WeakMap();
return (_interopRequireWildcard = function (e, t) {
if (!t && e && e.__esModule) return e;
var o,
i,
f = { __proto__: null, default: e };
if (null === e || ("object" != typeof e && "function" != typeof e))
return f;
if ((o = t ? n : r)) {
if (o.has(e)) return o.get(e);
o.set(e, f);
}
for (const t in e)
"default" !== t &&
{}.hasOwnProperty.call(e, t) &&
((i =
(o = Object.defineProperty) &&
Object.getOwnPropertyDescriptor(e, t)) &&
(i.get || i.set)
? o(f, t, i)
: (f[t] = e[t]));
return f;
})(e, t);
}
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
async function runServer(_argv, cliConfig, args) {
const metroConfig = await (0, _loadMetroConfig.default)(cliConfig, {
config: args.config,
maxWorkers: args.maxWorkers,
port: args.port,
resetCache: args.resetCache,
watchFolders: args.watchFolders,
projectRoot: args.projectRoot,
sourceExts: args.sourceExts,
});
const hostname = args.host?.length ? args.host : "localhost";
const {
projectRoot,
server: { port },
watchFolders,
} = metroConfig;
const protocol = args.https === true ? "https" : "http";
const devServerUrl = _url.default.format({
protocol,
hostname,
port,
});
console.info(
(0, _util.styleText)(
"blue",
`\nWelcome to React Native v${cliConfig.reactNativeVersion}`,
),
);
const serverStatus = await (0, _isDevServerRunning.default)(
devServerUrl,
projectRoot,
);
if (serverStatus === "matched_server_running") {
console.info(
`A dev server is already running for this project on port ${port}. Exiting.`,
);
return;
} else if (serverStatus === "port_taken") {
console.error(
`${(0, _util.styleText)("red", "error")}: Another process is running on port ${port}. Please terminate this ` +
'process and try again, or use another port with "--port".',
);
return;
}
console.info(`Starting dev server on ${devServerUrl}\n`);
if (args.assetPlugins) {
metroConfig.transformer.assetPlugins = args.assetPlugins.map((plugin) =>
require.resolve(plugin),
);
}
if (!args.clientLogs) {
metroConfig.server.forwardClientLogs = false;
}
let reportEvent;
const terminal = new _metroCore.Terminal(process.stdout);
const ReporterImpl = getReporterImpl(args.customLogReporterPath);
const terminalReporter = new ReporterImpl(terminal);
const {
middleware: communityMiddleware,
websocketEndpoints: communityWebsocketEndpoints,
messageSocketEndpoint,
eventsSocketEndpoint,
} = (0, _middleware.createDevServerMiddleware)({
host: hostname,
port,
watchFolders,
});
const { middleware, websocketEndpoints } = (0,
_devMiddleware.createDevMiddleware)({
serverBaseUrl: devServerUrl,
logger: (0, _createDevMiddlewareLogger.default)(terminalReporter),
});
metroConfig.reporter = {
update(event) {
terminalReporter.update(event);
if (reportEvent) {
reportEvent(event);
}
if (args.interactive && event.type === "initialize_done") {
terminalReporter.update({
type: "unstable_server_log",
level: "info",
data: `Dev server ready. ${(0, _util.styleText)("dim", "Press Ctrl+C to exit.")}`,
});
(0, _attachKeyHandlers.default)({
devServerUrl,
messageSocket: messageSocketEndpoint,
reporter: terminalReporter,
});
}
},
};
await _metro.default.runServer(metroConfig, {
host: args.host,
secure: args.https,
secureCert: args.cert,
secureKey: args.key,
unstable_extraMiddleware: [communityMiddleware, middleware],
websocketEndpoints: {
...communityWebsocketEndpoints,
...websocketEndpoints,
},
});
reportEvent = eventsSocketEndpoint.reportEvent;
await version.logIfUpdateAvailable(cliConfig, terminalReporter);
}
function getReporterImpl(customLogReporterPath) {
if (customLogReporterPath == null) {
return require("metro").TerminalReporter;
}
try {
return require(customLogReporterPath);
} catch (e) {
if (e.code !== "MODULE_NOT_FOUND") {
throw e;
}
return require(_path.default.resolve(customLogReporterPath));
}
}
var _default = (exports.default = runServer);

View File

@@ -0,0 +1,38 @@
/**
* 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
*/
import type { Config } from "@react-native-community/cli-types";
export type StartCommandArgs = {
assetPlugins?: string[],
cert?: string,
customLogReporterPath?: string,
host?: string,
https?: boolean,
maxWorkers?: number,
key?: string,
platforms: string[],
port?: number,
resetCache?: boolean,
sourceExts?: string[],
transformer?: string,
watchFolders?: string[],
config?: string,
projectRoot?: string,
interactive: boolean,
clientLogs: boolean,
};
declare function runServer(
_argv: Array<string>,
cliConfig: Config,
args: StartCommandArgs,
): void;
declare export default typeof runServer;