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

13
node_modules/@react-native/debugger-shell/README.md generated vendored Normal file
View File

@@ -0,0 +1,13 @@
# @react-native/debugger-shell
![npm package](https://img.shields.io/npm/v/@react-native/debugger-shell?color=brightgreen&label=npm%20package)
Experimental Electron-based shell for React Native DevTools. This package is not part of React Native's public API.
## Why Electron?
The React Native DevTools frontend is based on Chrome DevTools, which is a web app, but is not particularly portable: it's designed to run in Chromium, and Chromium only. Prior to `@react-native/debugger-shell`, we would run it in [hosted mode](https://chromium.googlesource.com/devtools/devtools-frontend/+/main/docs/get_the_code.md#running-in-hosted-mode) in an instance of Chrome or Edge.
Relying on hosted mode presents a variety of UX issues in the debugging workflow, such as the need to ask developers to install a particular browser before they can debug in React Native, and the inability to foreground/reuse existing debugger windows when relaunching the debugger for the same app. In order to address these issues effectively, we fundamentally need to leave the browser sandbox and run the debugger in a shell we can bundle with React Native, and whose behavior we can control.
Electron is a tried-and-tested framework for the *specific* task of embedding a Chromium browser in a portable, customized shell. As a rule we'll hold a high bar for performance and reliability, and we'll only add features to the shell if they are strictly necessary to complement the DevTools frontend's built-in capabilities.

View File

@@ -0,0 +1,90 @@
#!/usr/bin/env dotslash
// @generated SignedSource<<618e5a37a696ed5aa07badb7fad5de33>>
{
"name": "React Native DevTools",
"platforms": {
"linux-aarch64": {
"size": 116051181,
"hash": "sha256",
"digest": "a6060e1291f9ee7e9feecd511012c041ed2a65c6df6f8ab5aca4d96adbbc9921",
"providers": [
{
"url": "https://github.com/facebook/react-native/releases/download/v0.83.2/React.Native.DevTools-linux-aarch64.tar.gz"
},
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQOD3-UmqD25MctpnB7Ogj0A8nHDs-SgFnMNFfStIxOajFAFSN93zuoWsLD3ylc3wVuX6-L-ndcMftTd7tlR1ZZWYy4a7g78w4N1UTzIT_z9vdOXpYGe7fZrHXiBHJu0QexD0b54OcdDSEFhh0-7puUTGPnIg3pHhThiU6bf_5AqvGIEYA5FGjih3zY"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-arm64/React Native DevTools"
},
"linux-x86_64": {
"size": 115927343,
"hash": "sha256",
"digest": "354f6550617d0c6b4bb4478ad085d4efe3671ba9a1b78d90d9bfc003a523cb6d",
"providers": [
{
"url": "https://github.com/facebook/react-native/releases/download/v0.83.2/React.Native.DevTools-linux-x86_64.tar.gz"
},
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQMVMfCfSykWSI8mB5koUEUtx819xGQGW3Tm1DBpEmjWA_g8C4PoPPDCIPpgJmB5nUKrv081_dtayoArCncyFJVs0ofbxGn0EkaEW2vW3OJ2J0XMH58v5cTLED3dT8TmWwAg6aYUTr0ch8DfVXRxsibYUIWaxJUwOJ-urR-iQm7YPQUboLElaJbM"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-x64/React Native DevTools"
},
"macos-aarch64": {
"size": 110891048,
"hash": "sha256",
"digest": "df41cfce9bc977ef4fdc66c3c892c0eedee5b07aa618550308157c51b8e75561",
"providers": [
{
"url": "https://github.com/facebook/react-native/releases/download/v0.83.2/React.Native.DevTools-macos-aarch64.tar.gz"
},
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQOGfzOOV_mwg63orI4Hv0VQKQtE5Vk60eSl55gZDd0djjU-lmqddRZm_LxsWsek4xM7qIxqCbw6wGx7zqnrlmQGyfD98n0TBFh3uhVeYP_j3r2UkKci6tqjEqcLTHjFj3agjI6jDEe3fDpZtwKY4UMhXdVP4o1goYq13rG-IQAqIsAm04MnPFOYyp5X"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"macos-x86_64": {
"size": 117777930,
"hash": "sha256",
"digest": "96805c51623a163b1d94b501e2e091f403b4c3575063bd7363f8e1550cda8dc5",
"providers": [
{
"url": "https://github.com/facebook/react-native/releases/download/v0.83.2/React.Native.DevTools-macos-x86_64.tar.gz"
},
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQNbF-vba13QuctGdSckSWSApEqUne0w8vGceEm5u9VNYqHzwaZu6_T0n12Ml7aHuNgAgU0OOxJKUjcr2DVsNEsjcCYwMqCjZys8yF8NfM39OH1YePjHZCw5jinydbhGxhF1zbJ_zKmuOx1FhJtzCD3CUbLSea7fuhPh6ytLUIu3Ctx4aFQLFtbJZQ"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"windows-x86_64": {
"size": 125533589,
"hash": "sha256",
"digest": "7f560e6d68b4b917c53ba0518a778a20e267cce55474ad972d345b2738746a52",
"providers": [
{
"url": "https://github.com/facebook/react-native/releases/download/v0.83.2/React.Native.DevTools-windows-x86_64.tar.gz"
},
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPZzccNNBkp1OKt_SPZ-iDoK5LDWyvZhFMgz4oTf9Ja9PlKU7i_5ydAVd714waJteCM1cdAidPN6PumBRs1uK12E9moytEskWXlMPbQObFpaTnkxLn6xp3N5EAKbAXvPfecX41Tz_7HRqh19_hW3XpwXF-VNsAdtn59ApMtX1fpN0peB1l4o57P"
}
],
"format": "tar.gz",
"path": "React Native DevTools-win32-x64/React Native DevTools.exe"
}
}
}

View File

@@ -0,0 +1,14 @@
/**
* 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
*/
declare const $$EXPORT_DEFAULT_DECLARATION$$: { revision: "dev" };
declare type $$EXPORT_DEFAULT_DECLARATION$$ =
typeof $$EXPORT_DEFAULT_DECLARATION$$;
export default $$EXPORT_DEFAULT_DECLARATION$$;

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = void 0;
var _default = (exports.default = {
revision: "dev",
});

View File

@@ -0,0 +1,11 @@
/**
* 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
*/
declare export default { revision: "dev" };

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.
*
* %s
* @flow strict-local
* @format
*/
'use strict';
module.exports = {
default: {
revision: %s,
},
__esModule: true,
};

View File

@@ -0,0 +1,9 @@
/**
* 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
*/

View File

@@ -0,0 +1,162 @@
"use strict";
var _SettingsStore = _interopRequireDefault(require("./SettingsStore.js"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
const path = require("path");
const util = require("util");
const { BrowserWindow, Menu, app, shell, ipcMain } = require("electron");
const appSettings = new _SettingsStore.default();
const windowMetadata = new WeakMap();
function handleLaunchArgs(argv) {
const {
values: { frontendUrl, windowKey },
} = util.parseArgs({
options: {
frontendUrl: {
type: "string",
},
windowKey: {
type: "string",
},
},
args: argv,
});
let frontendWindow = BrowserWindow.getAllWindows().find((window) => {
const metadata = windowMetadata.get(window);
if (!metadata) {
return false;
}
return metadata.windowKey === windowKey;
});
if (frontendWindow) {
if (frontendWindow.isVisible()) {
frontendWindow.flashFrame(true);
setTimeout(() => {
frontendWindow.flashFrame(false);
}, 1000);
}
} else {
frontendWindow = new BrowserWindow({
...(getSavedWindowPosition(windowKey) ?? {
width: 1200,
height: 600,
}),
webPreferences: {
partition: "persist:react-native-devtools",
preload: require.resolve("./preload.js"),
},
icon: path.join(__dirname, "resources", "icon.png"),
});
frontendWindow.setMenuBarVisibility(false);
setupWindowResizeListeners(frontendWindow, windowKey);
}
frontendWindow.webContents.setWindowOpenHandler(({ url }) => {
shell.openExternal(url);
return {
action: "deny",
};
});
frontendWindow.loadURL(frontendUrl);
windowMetadata.set(frontendWindow, {
windowKey,
});
if (process.platform === "darwin") {
app.focus({
steal: true,
});
}
frontendWindow.focus();
}
function configureAppMenu() {
const template = [
...(process.platform === "darwin"
? [
{
role: "appMenu",
},
]
: []),
{
role: "fileMenu",
},
{
role: "editMenu",
},
{
role: "viewMenu",
},
{
role: "windowMenu",
},
{
role: "help",
submenu: [
{
label: "React Native Website",
click: () => shell.openExternal("https://reactnative.dev"),
},
{
label: "Release Notes",
click: () =>
shell.openExternal(
"https://github.com/facebook/react-native/releases",
),
},
],
},
];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
function getSavedWindowPosition(windowKey) {
return appSettings.get("windowArrangements", {})[windowKey];
}
function saveWindowPosition(windowKey, position) {
const windowArrangements = appSettings.get("windowArrangements", {});
windowArrangements[windowKey] = position;
appSettings.set("windowArrangements", windowArrangements);
}
function setupWindowResizeListeners(browserWindow, windowKey) {
const savePosition = () => {
if (!browserWindow.isDestroyed()) {
const [x, y] = browserWindow.getPosition();
const [width, height] = browserWindow.getSize();
saveWindowPosition(windowKey, {
x,
y,
width,
height,
});
}
};
browserWindow.on("moved", savePosition);
browserWindow.on("resized", savePosition);
browserWindow.on("closed", savePosition);
}
app.whenReady().then(() => {
handleLaunchArgs(process.argv.slice(app.isPackaged ? 1 : 2));
configureAppMenu();
app.on(
"second-instance",
(event, electronArgv, workingDirectory, additionalData) => {
handleLaunchArgs(additionalData.argv);
},
);
});
app.on("window-all-closed", function () {
app.quit();
});
ipcMain.on("bringToFront", (event, title) => {
const webContents = event.sender;
const win = BrowserWindow.fromWebContents(webContents);
if (win) {
win.focus();
}
if (process.platform === "darwin") {
app.focus({
steal: true,
});
}
});

View File

@@ -0,0 +1,9 @@
/**
* 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
*/

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.
*
*
* @format
* @oncall react_native
*/
type Options = Readonly<{ name?: string; defaults?: Object }>;
/**
* A data persistence layer for storing application settings, modelled after
* [`electron-store`](https://www.npmjs.com/package/electron-store).
*
* Values are saved in a `config.json` file in `app.getPath('userData')`.
*
* Compatibility:
* - Maintains API and file format compatibility with `electron-store@8.2.0`.
* - Supports the Electron main process only.
*/
declare class SettingsStore {
path: string;
constructor(options?: Options);
get(key: string, defaultValue?: any): any;
set(key: string, value: any): void;
has(key: string): boolean;
reset(...keys: Array<string>): void;
delete(key: string): void;
clear(): void;
get store(): { [$$Key$$: string]: unknown };
set store(value: unknown);
_deserialize: (value: string) => unknown;
_serialize: (value: unknown) => string;
_ensureDirectory(): void;
_write(value: unknown): void;
}
export default SettingsStore;

View File

@@ -0,0 +1,95 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = void 0;
const { app } = require("electron");
const fs = require("fs");
const path = require("path");
class SettingsStore {
#defaultValues = {};
constructor(options = {}) {
options = {
name: "config",
...options,
};
this.#defaultValues = {
...this.#defaultValues,
...options.defaults,
};
this.path = path.resolve(
app.getPath("userData"),
`${options.name ?? "config"}.json`,
);
}
get(key, defaultValue) {
const store = this.store;
return store[key] !== undefined ? store[key] : defaultValue;
}
set(key, value) {
const { store } = this;
if (typeof key === "object") {
for (const [k, v] of Object.entries(key)) {
store[k] = v;
}
} else {
store[key] = value;
}
this.store = store;
}
has(key) {
return key in this.store;
}
reset(...keys) {
for (const key of keys) {
if (this.#defaultValues[key] != null) {
this.set(key, this.#defaultValues[key]);
}
}
}
delete(key) {
const { store } = this;
delete store[key];
this.store = store;
}
clear() {
this.store = {};
for (const key of Object.keys(this.#defaultValues)) {
this.reset(key);
}
}
get store() {
try {
const data = fs.readFileSync(this.path, "utf8");
const deserializedData = this._deserialize(data);
return {
...deserializedData,
};
} catch (error) {
if (error?.code === "ENOENT") {
this._ensureDirectory();
return {};
}
throw error;
}
}
set store(value) {
this._ensureDirectory();
this._write(value);
}
_deserialize = (value) => JSON.parse(value);
_serialize = (value) => JSON.stringify(value, undefined, "\t") ?? "";
_ensureDirectory() {
fs.mkdirSync(path.dirname(this.path), {
recursive: true,
});
}
_write(value) {
const data = this._serialize(value);
fs.writeFileSync(this.path, data, {
mode: 0o666,
});
}
}
exports.default = SettingsStore;

View File

@@ -0,0 +1,42 @@
/**
* 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
* @format
* @oncall react_native
*/
type Options = $ReadOnly<{
name?: string,
defaults?: Object,
}>;
/**
* A data persistence layer for storing application settings, modelled after
* [`electron-store`](https://www.npmjs.com/package/electron-store).
*
* Values are saved in a `config.json` file in `app.getPath('userData')`.
*
* Compatibility:
* - Maintains API and file format compatibility with `electron-store@8.2.0`.
* - Supports the Electron main process only.
*/
declare export default class SettingsStore {
path: string;
constructor(options?: Options): void;
get(key: string, defaultValue?: any): any;
set(key: string, value: any): void;
has(key: string): boolean;
reset(...keys: Array<string>): void;
delete(key: string): void;
clear(): void;
get store(): { [string]: mixed };
set store(value: mixed): void;
_deserialize: (value: string) => mixed;
_serialize: (value: mixed) => string;
_ensureDirectory(): void;
_write(value: mixed): void;
}

View File

@@ -0,0 +1,9 @@
/**
* 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
*/

View File

@@ -0,0 +1,34 @@
"use strict";
var _BuildInfo = _interopRequireDefault(require("./BuildInfo"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
const pkg = require("../../package.json");
const util = require("util");
const { app } = require("electron");
app.setName(pkg.productName ?? pkg.name);
app.setVersion(pkg.version + "-" + _BuildInfo.default.revision);
const {
values: { version = false },
} = util.parseArgs({
options: {
version: {
type: "boolean",
},
},
args: process.argv.slice(app.isPackaged ? 1 : 2),
strict: false,
});
if (version) {
console.log(`${pkg.name} v${app.getVersion()}`);
app.exit(0);
}
const gotTheLock = app.requestSingleInstanceLock({
argv: process.argv.slice(app.isPackaged ? 1 : 2),
});
if (!gotTheLock) {
app.quit();
} else {
require("./MainInstanceEntryPoint.js");
}

View File

@@ -0,0 +1,9 @@
/**
* 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
*/

View File

@@ -0,0 +1,9 @@
/**
* 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
*/

View File

@@ -0,0 +1,31 @@
"use strict";
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.executeInMainWorld({
func: (ipcDevTools) => {
let didDecorateInspectorFrontendHostInstance = false;
globalThis.reactNativeDecorateInspectorFrontendHostInstance = (
InspectorFrontendHostInstance,
) => {
didDecorateInspectorFrontendHostInstance = true;
InspectorFrontendHostInstance.bringToFront = () => {
ipcDevTools.bringToFront();
};
};
document.addEventListener("DOMContentLoaded", () => {
if (!didDecorateInspectorFrontendHostInstance) {
console.error(
"reactNativeDecorateInspectorFrontendHostInstance was not called at startup. " +
"This version of the DevTools frontend may not be compatible with @react-native/debugger-shell.",
);
}
});
},
args: [
{
bringToFront() {
ipcRenderer.send("bringToFront");
},
},
],
});

View File

@@ -0,0 +1,9 @@
/**
* 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
*/

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@@ -0,0 +1,9 @@
/**
* 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
*/

View File

@@ -0,0 +1,7 @@
"use strict";
if ("electron" in process.versions) {
module.exports = require("./electron");
} else {
module.exports = require("./node");
}

View File

@@ -0,0 +1,9 @@
/**
* 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
*/

View File

@@ -0,0 +1,46 @@
/**
* 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?: string;
}>,
): 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(
flavor: DebuggerShellFlavor,
$$PARAM_1$$?: { prebuiltBinaryPath?: string },
): Promise<DebuggerShellPreparationResult>;
export { unstable_spawnDebuggerShellWithArgs, unstable_prepareDebuggerShell };

View File

@@ -0,0 +1,120 @@
"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 path = require("path");
const DEVTOOLS_BINARY_DOTSLASH_FILE = path.join(
__dirname,
"../../bin/react-native-devtools",
);
async function unstable_spawnDebuggerShellWithArgs(
args,
{ mode = "detached", flavor = "prebuilt", prebuiltBinaryPath } = {},
) {
const [binaryPath, baseArgs] = getShellBinaryAndArgs(
flavor,
prebuiltBinaryPath,
);
return new Promise((resolve, reject) => {
const child = spawn(binaryPath, [...baseArgs, ...args], {
stdio: "inherit",
windowsHide: true,
detached: mode === "detached",
});
if (mode === "detached") {
child.on("spawn", () => {
resolve();
});
child.on("close", (code) => {
if (code !== 0) {
reject(
new Error(
`Failed to open debugger shell: exited with code ${code}`,
),
);
}
});
child.unref();
} else if (mode === "syncThenExit") {
child.on("close", function (code, signal) {
if (code === null) {
console.error("Debugger shell exited with signal", signal);
process.exit(1);
}
process.exit(code);
});
const handleTerminationSignal = function (signal) {
process.on(signal, function signalHandler() {
if (!child.killed) {
child.kill(signal);
}
});
};
handleTerminationSignal("SIGINT");
handleTerminationSignal("SIGTERM");
}
});
}
async function unstable_prepareDebuggerShell(
flavor,
{ prebuiltBinaryPath } = {},
) {
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,56 @@
/**
* 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,
}>,
): 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(
flavor: DebuggerShellFlavor,
$$PARAM_1$$?: { prebuiltBinaryPath?: string },
): 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 occured 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 };

46
node_modules/@react-native/debugger-shell/package.json generated vendored Normal file
View File

@@ -0,0 +1,46 @@
{
"name": "@react-native/debugger-shell",
"productName": "React Native DevTools",
"version": "0.83.2",
"description": "Experimental debugger shell for React Native for use with @react-native/debugger-frontend",
"keywords": [
"react-native",
"tools"
],
"homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/debugger-shell#readme",
"bugs": "https://github.com/facebook/react-native/issues",
"main": "./dist/index.js",
"exports": {
".": {
"node": "./dist/node/index.js",
"electron": "./dist/electron/index.js"
},
"./package.json": "./package.json"
},
"scripts": {
"dev": "electron src/electron"
},
"repository": {
"type": "git",
"url": "git+https://github.com/facebook/react-native.git",
"directory": "packages/debugger-shell"
},
"license": "MIT",
"engines": {
"node": ">= 20.19.4"
},
"dependencies": {
"cross-spawn": "^7.0.6",
"fb-dotslash": "0.5.8"
},
"devDependencies": {
"electron": "37.2.6",
"semver": "^7.1.3"
},
"files": [
"!**/__tests__/**",
"bin",
"dist",
"!src/electron"
]
}