FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

View File

@@ -0,0 +1,47 @@
/**
* 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.
*
*
* @format
*/
type DebuggerShellFlavor = "prebuilt" | "dev";
declare function unstable_spawnDebuggerShellWithArgs(
args: string[],
$$PARAM_1$$?: Readonly<{
mode?: "syncThenExit" | "detached";
flavor?: DebuggerShellFlavor;
prebuiltBinaryPath?: null | undefined | string;
silent?: boolean;
}>,
): Promise<void>;
export type DebuggerShellPreparationResult = Readonly<{
code:
| "success"
| "not_implemented"
| "likely_offline"
| "platform_not_supported"
| "possible_corruption"
| "unexpected_error";
humanReadableMessage?: string;
verboseInfo?: string;
}>;
/**
* Attempts to prepare the debugger shell for use and returns a coded result
* that can be used to advise the user on how to proceed in case of failure.
* In particular, this function will attempt to download and extract an
* appropriate binary for the "prebuilt" flavor.
*
* This function should be called early during dev server startup, in parallel
* with other initialization steps, so that the debugger shell is ready to use
* instantly when the user tries to open it (and conversely, the user is
* informed ASAP if it is not ready to use).
*/
declare function unstable_prepareDebuggerShell($$PARAM_0$$?: {
prebuiltBinaryPath?: null | undefined | string;
flavor?: DebuggerShellFlavor;
}): Promise<DebuggerShellPreparationResult>;
export { unstable_spawnDebuggerShellWithArgs, unstable_prepareDebuggerShell };

View File

@@ -0,0 +1,155 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.unstable_prepareDebuggerShell = unstable_prepareDebuggerShell;
exports.unstable_spawnDebuggerShellWithArgs =
unstable_spawnDebuggerShellWithArgs;
var _LaunchUtils = require("./private/LaunchUtils");
const { spawn } = require("cross-spawn");
const debug = require("debug")("Metro:DebuggerShell");
const path = require("path");
const DEVTOOLS_BINARY_DOTSLASH_FILE = path.join(
__dirname,
"../../bin/react-native-devtools",
);
async function unstable_spawnDebuggerShellWithArgs(
args,
{
mode = "detached",
flavor = process.env.RNDT_DEV === "1" ? "dev" : "prebuilt",
prebuiltBinaryPath,
silent = process.env.NODE_ENV === "test",
} = {},
) {
const [binaryPath, baseArgs] = getShellBinaryAndArgs(
flavor,
prebuiltBinaryPath,
);
return new Promise((resolve, reject) => {
const { ELECTRON_RUN_AS_NODE: _, ...env } = process.env;
const child = spawn(binaryPath, [...baseArgs, ...args], {
stdio: ["ignore", "pipe", "pipe"],
windowsHide: true,
detached: mode === "detached",
env,
});
if (mode === "detached") {
child.on("spawn", () => {
debug("Debugger spawned in detached mode");
resolve();
});
child.on("close", (code, signal) => {
debug("Debugger closed with code %s and signal %s", code, signal);
if (code !== 0) {
if (!silent) {
console.error(
"Debugger exited with non-zero code (code: %s, signal: %s)",
code,
signal,
);
}
reject(
new Error(
`Failed to open debugger shell: exited with code ${code}`,
),
);
}
});
child.on("error", (error) => {
debug("Debugger shell encountered error: %s", error);
reject(error);
});
if (!silent) {
child.stdout.on("data", (data) =>
console.log("[debugger-shell stdout] " + String(data)),
);
child.stderr.on("data", (data) =>
console.warn("[debugger-shell stderr] " + String(data)),
);
}
child.unref();
} else if (mode === "syncThenExit") {
child.on("close", function (code, signal) {
debug("Debugger exited with code %s and signal %s", code, signal);
if (code == null && !silent) {
console.error(
"Debugger exited with code %s and signal %s",
code,
signal,
);
process.exit(1);
}
process.exit(code);
});
const handleTerminationSignal = function (signal) {
process.on(signal, function signalHandler() {
debug("Received signal %s. Killing debugger shell.", signal);
if (!child.killed) {
child.kill(signal);
}
});
};
handleTerminationSignal("SIGINT");
handleTerminationSignal("SIGTERM");
}
});
}
async function unstable_prepareDebuggerShell({
prebuiltBinaryPath,
flavor = process.env.RNDT_DEV === "1" ? "dev" : "prebuilt",
} = {}) {
try {
switch (flavor) {
case "prebuilt":
const prebuiltResult = await (0,
_LaunchUtils.prepareDebuggerShellFromDotSlashFile)(
prebuiltBinaryPath ?? DEVTOOLS_BINARY_DOTSLASH_FILE,
);
if (prebuiltResult.code !== "success") {
return prebuiltResult;
}
break;
case "dev":
break;
default:
throw new Error(`Unknown flavor: ${flavor}`);
}
const [binaryPath, baseArgs] = getShellBinaryAndArgs(
flavor,
prebuiltBinaryPath,
);
const { code, stderr } = await (0, _LaunchUtils.spawnAndGetStderr)(
binaryPath,
[...baseArgs, "--version"],
);
if (code !== 0) {
return {
code: "unexpected_error",
verboseInfo: stderr,
};
}
return {
code: "success",
};
} catch (e) {
return {
code: "unexpected_error",
verboseInfo: e.message,
};
}
}
function getShellBinaryAndArgs(flavor, prebuiltBinaryPath) {
switch (flavor) {
case "prebuilt":
return [
require("fb-dotslash"),
[prebuiltBinaryPath ?? DEVTOOLS_BINARY_DOTSLASH_FILE],
];
case "dev":
return [require("electron"), [require.resolve("../electron")]];
default:
throw new Error(`Unknown flavor: ${flavor}`);
}
}

View File

@@ -0,0 +1,57 @@
/**
* 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
*/
// The 'prebuilt' flavor will use the prebuilt shell binary (and the JavaScript embedded in it).
// The 'dev' flavor will use a stock Electron binary and run the shell code from the `electron/` directory.
type DebuggerShellFlavor = "prebuilt" | "dev";
declare function unstable_spawnDebuggerShellWithArgs(
args: string[],
$$PARAM_1$$?: Readonly<{
// In 'syncAndExit' mode, the current process will block until the spawned process exits, and then it will exit
// with the same exit code as the spawned process.
// In 'detached' mode, the spawned process will be detached from the current process and the current process will
// continue to run normally.
mode?: "syncThenExit" | "detached",
flavor?: DebuggerShellFlavor,
prebuiltBinaryPath?: ?string,
silent?: boolean,
}>,
): Promise<void>;
export type DebuggerShellPreparationResult = Readonly<{
code:
| "success"
| "not_implemented"
| "likely_offline"
| "platform_not_supported"
| "possible_corruption"
| "unexpected_error",
humanReadableMessage?: string,
verboseInfo?: string,
}>;
/**
* Attempts to prepare the debugger shell for use and returns a coded result
* that can be used to advise the user on how to proceed in case of failure.
* In particular, this function will attempt to download and extract an
* appropriate binary for the "prebuilt" flavor.
*
* This function should be called early during dev server startup, in parallel
* with other initialization steps, so that the debugger shell is ready to use
* instantly when the user tries to open it (and conversely, the user is
* informed ASAP if it is not ready to use).
*/
declare function unstable_prepareDebuggerShell($$PARAM_0$$?: {
prebuiltBinaryPath?: ?string,
flavor?: DebuggerShellFlavor,
}): Promise<DebuggerShellPreparationResult>;
export { unstable_spawnDebuggerShellWithArgs, unstable_prepareDebuggerShell };

View File

@@ -0,0 +1,19 @@
/**
* 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.
*
*
* @format
*/
import type { DebuggerShellPreparationResult } from "../";
declare function spawnAndGetStderr(
command: string,
args: string[],
): Promise<{ code: number; stderr: string }>;
declare function prepareDebuggerShellFromDotSlashFile(
filePath: string,
): Promise<DebuggerShellPreparationResult>;
export { spawnAndGetStderr, prepareDebuggerShellFromDotSlashFile };

View File

@@ -0,0 +1,84 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.prepareDebuggerShellFromDotSlashFile =
prepareDebuggerShellFromDotSlashFile;
exports.spawnAndGetStderr = spawnAndGetStderr;
const { spawn } = require("cross-spawn");
async function spawnAndGetStderr(command, args) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, {
stdio: ["ignore", "ignore", "pipe"],
encoding: "utf8",
windowsHide: true,
});
let stderr = "";
child.stderr.on("data", (data) => {
stderr += data;
});
child.on("error", (error) => {
reject(error);
});
child.on("close", (code, signal) => {
resolve({
code,
stderr,
});
});
});
}
async function prepareDebuggerShellFromDotSlashFile(filePath) {
const { code, stderr } = await spawnAndGetStderr(require("fb-dotslash"), [
"--",
"fetch",
filePath,
]);
if (code === 0) {
return {
code: "success",
};
}
if (
stderr.includes("dotslash error") &&
stderr.includes("no providers succeeded")
) {
if (stderr.includes("failed to verify artifact")) {
return {
code: "possible_corruption",
humanReadableMessage:
"Failed to verify the latest version of React Native DevTools. " +
"Using a fallback version instead. ",
verboseInfo: stderr,
};
}
return {
code: "likely_offline",
humanReadableMessage:
"Failed to download the latest version of React Native DevTools. " +
"Using a fallback version instead. " +
"Connect to the internet or check your network settings.",
verboseInfo: stderr,
};
}
if (
stderr.includes("dotslash error") &&
stderr.includes("platform not supported")
) {
return {
code: "platform_not_supported",
humanReadableMessage:
"The latest version of React Native DevTools is not supported on this platform. " +
"Using a fallback version instead.",
verboseInfo: stderr,
};
}
return {
code: "unexpected_error",
humanReadableMessage:
"An unexpected error occurred while installing the latest version of React Native DevTools. " +
"Using a fallback version instead.",
verboseInfo: stderr,
};
}

View File

@@ -0,0 +1,25 @@
/**
* 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 { DebuggerShellPreparationResult } from "../";
declare function spawnAndGetStderr(
command: string,
args: string[],
): Promise<{
code: number,
stderr: string,
}>;
declare function prepareDebuggerShellFromDotSlashFile(
filePath: string,
): Promise<DebuggerShellPreparationResult>;
export { spawnAndGetStderr, prepareDebuggerShellFromDotSlashFile };