{compiledWithForget && 
}
 
+      {environmentName != null ? 
{environmentName} : null}
+
       {hocDisplayNames != null && hocDisplayNames.length > 0 && (
         
{hocDisplayNames[0]}
       )}
diff --git a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js
index a1b76e49b6add..c24dd881e9891 100644
--- a/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js
+++ b/packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSuspendedBy.js
@@ -150,13 +150,28 @@ function SuspendedByRow({
       
       {isOpen && (
         
-          {showIOStack && 
}
+          {showIOStack && (
+            
+          )}
           {(showIOStack || !showAwaitStack) &&
           ioOwner !== null &&
           ioOwner.id !== inspectedElement.id ? (
             
               awaited at:
               {asyncInfo.stack !== null && asyncInfo.stack.length > 0 && (
-                
+                
               )}
               {asyncOwner !== null && asyncOwner.id !== inspectedElement.id ? (
                  | null,
+  environmentName: string | null,
   compiledWithForget: boolean,
   id: number,
   isInStore: boolean,
@@ -27,6 +28,7 @@ type OwnerViewProps = {
 
 export default function OwnerView({
   displayName,
+  environmentName,
   hocDisplayNames,
   compiledWithForget,
   id,
@@ -65,6 +67,7 @@ export default function OwnerView({
         
       
     
diff --git a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js
index 0fa5c0910bb6e..09bdb96af01cd 100644
--- a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js
+++ b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js
@@ -220,6 +220,7 @@ function ElementsDropdown({owners, selectOwner}: ElementsDropdownProps) {
 
         
@@ -268,6 +269,7 @@ function ElementView({isSelected, owner, selectOwner}: ElementViewProps) {
 
       
diff --git a/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.js b/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.js
index 4352ad6a827d9..fdbdba702dafb 100644
--- a/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.js
+++ b/packages/react-devtools-shared/src/devtools/views/Components/StackTraceView.js
@@ -12,6 +12,8 @@ import {use, useContext} from 'react';
 
 import useOpenResource from '../useOpenResource';
 
+import ElementBadges from './ElementBadges';
+
 import styles from './StackTraceView.css';
 
 import type {
@@ -28,9 +30,13 @@ import formatLocationForDisplay from './formatLocationForDisplay';
 
 type CallSiteViewProps = {
   callSite: ReactCallSite,
+  environmentName: null | string,
 };
 
-export function CallSiteView({callSite}: CallSiteViewProps): React.Node {
+export function CallSiteView({
+  callSite,
+  environmentName,
+}: CallSiteViewProps): React.Node {
   const fetchFileWithCaching = useContext(FetchFileWithCachingContext);
 
   const [virtualFunctionName, virtualURL, virtualLine, virtualColumn] =
@@ -64,19 +70,33 @@ export function CallSiteView({callSite}: CallSiteViewProps): React.Node {
         title={url + ':' + line}>
         {formatLocationForDisplay(url, line, column)}
       
+      
     
   );
 }
 
 type Props = {
   stack: ReactStackTrace,
+  environmentName: null | string,
 };
 
-export default function StackTraceView({stack}: Props): React.Node {
+export default function StackTraceView({
+  stack,
+  environmentName,
+}: Props): React.Node {
   return (
     
       {stack.map((callSite, index) => (
-        
+        
       ))}
     
   );
diff --git a/packages/react-devtools-shared/src/frontend/types.js b/packages/react-devtools-shared/src/frontend/types.js
index 622205dd672b7..e4a4c5400bfd5 100644
--- a/packages/react-devtools-shared/src/frontend/types.js
+++ b/packages/react-devtools-shared/src/frontend/types.js
@@ -208,6 +208,7 @@ export type SerializedElement = {
   displayName: string | null,
   id: number,
   key: number | string | null,
+  env: null | string,
   hocDisplayNames: Array
 | null,
   compiledWithForget: boolean,
   type: ElementType,
@@ -265,6 +266,9 @@ export type InspectedElement = {
   // List of owners
   owners: Array | null,
 
+  // Environment name that this component executed in or null for the client
+  env: string | null,
+
   // Location of component in source code.
   source: ReactFunctionLocation | null,
 
From 3958d5d84b3d3e6ae5c1caef9c8cf0dc58e862e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= 
Date: Thu, 7 Aug 2025 10:55:01 -0400
Subject: [PATCH 4/4] [Flight] Copy the name field of a serialized function
 debug value (#34085)
This ensures that if the name is set manually after the declaration,
then we get that name when we log the value. For example Node.js
`Response` is declared as `_Response` and then later assigned a new
name.
We should probably really serialize all static enumerable properties but
"name" is non-enumerable so it's still a special case.
---
 .../react-client/src/ReactFlightClient.js     | 94 +++++++++++++------
 .../src/__tests__/ReactFlight-test.js         |  3 +
 .../react-server/src/ReactFlightServer.js     | 13 ++-
 3 files changed, 78 insertions(+), 32 deletions(-)
diff --git a/packages/react-client/src/ReactFlightClient.js b/packages/react-client/src/ReactFlightClient.js
index fe88fe0357be7..c4d47bfecc55d 100644
--- a/packages/react-client/src/ReactFlightClient.js
+++ b/packages/react-client/src/ReactFlightClient.js
@@ -1969,6 +1969,44 @@ function createModel(response: Response, model: any): any {
   return model;
 }
 
+const mightHaveStaticConstructor = /\bclass\b.*\bstatic\b/;
+
+function getInferredFunctionApproximate(code: string): () => void {
+  let slicedCode;
+  if (code.startsWith('Object.defineProperty(')) {
+    slicedCode = code.slice('Object.defineProperty('.length);
+  } else if (code.startsWith('(')) {
+    slicedCode = code.slice(1);
+  } else {
+    slicedCode = code;
+  }
+  if (slicedCode.startsWith('async function')) {
+    const idx = slicedCode.indexOf('(', 14);
+    if (idx !== -1) {
+      const name = slicedCode.slice(14, idx).trim();
+      // eslint-disable-next-line no-eval
+      return (0, eval)('({' + JSON.stringify(name) + ':async function(){}})')[
+        name
+      ];
+    }
+  } else if (slicedCode.startsWith('function')) {
+    const idx = slicedCode.indexOf('(', 8);
+    if (idx !== -1) {
+      const name = slicedCode.slice(8, idx).trim();
+      // eslint-disable-next-line no-eval
+      return (0, eval)('({' + JSON.stringify(name) + ':function(){}})')[name];
+    }
+  } else if (slicedCode.startsWith('class')) {
+    const idx = slicedCode.indexOf('{', 5);
+    if (idx !== -1) {
+      const name = slicedCode.slice(5, idx).trim();
+      // eslint-disable-next-line no-eval
+      return (0, eval)('({' + JSON.stringify(name) + ':class{}})')[name];
+    }
+  }
+  return function () {};
+}
+
 function parseModelString(
   response: Response,
   parentObject: Object,
@@ -2158,41 +2196,37 @@ function parseModelString(
           // This should not compile to eval() because then it has local scope access.
           const code = value.slice(2);
           try {
-            // eslint-disable-next-line no-eval
-            return (0, eval)(code);
+            // If this might be a class constructor with a static initializer or
+            // static constructor then don't eval it. It might cause unexpected
+            // side-effects. Instead, fallback to parsing out the function type
+            // and name.
+            if (!mightHaveStaticConstructor.test(code)) {
+              // eslint-disable-next-line no-eval
+              return (0, eval)(code);
+            }
           } catch (x) {
-            // We currently use this to express functions so we fail parsing it,
-            // let's just return a blank function as a place holder.
-            if (code.startsWith('(async function')) {
-              const idx = code.indexOf('(', 15);
-              if (idx !== -1) {
-                const name = code.slice(15, idx).trim();
-                // eslint-disable-next-line no-eval
-                return (0, eval)(
-                  '({' + JSON.stringify(name) + ':async function(){}})',
-                )[name];
-              }
-            } else if (code.startsWith('(function')) {
-              const idx = code.indexOf('(', 9);
-              if (idx !== -1) {
-                const name = code.slice(9, idx).trim();
-                // eslint-disable-next-line no-eval
-                return (0, eval)(
-                  '({' + JSON.stringify(name) + ':function(){}})',
-                )[name];
-              }
-            } else if (code.startsWith('(class')) {
-              const idx = code.indexOf('{', 6);
+            // Fallthrough to fallback case.
+          }
+          // We currently use this to express functions so we fail parsing it,
+          // let's just return a blank function as a place holder.
+          let fn;
+          try {
+            fn = getInferredFunctionApproximate(code);
+            if (code.startsWith('Object.defineProperty(')) {
+              const DESCRIPTOR = ',"name",{value:"';
+              const idx = code.lastIndexOf(DESCRIPTOR);
               if (idx !== -1) {
-                const name = code.slice(6, idx).trim();
-                // eslint-disable-next-line no-eval
-                return (0, eval)('({' + JSON.stringify(name) + ':class{}})')[
-                  name
-                ];
+                const name = JSON.parse(
+                  code.slice(idx + DESCRIPTOR.length - 1, code.length - 2),
+                );
+                // $FlowFixMe[cannot-write]
+                Object.defineProperty(fn, 'name', {value: name});
               }
             }
-            return function () {};
+          } catch (_) {
+            fn = function () {};
           }
+          return fn;
         }
         // Fallthrough
       }
diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js
index 150997c1c3746..9a60c3bd66b29 100644
--- a/packages/react-client/src/__tests__/ReactFlight-test.js
+++ b/packages/react-client/src/__tests__/ReactFlight-test.js
@@ -3239,6 +3239,8 @@ describe('ReactFlight', () => {
     }
     Object.defineProperty(MyClass.prototype, 'y', {enumerable: true});
 
+    Object.defineProperty(MyClass, 'name', {value: 'MyClassName'});
+
     function ServerComponent() {
       console.log('hi', {
         prop: 123,
@@ -3341,6 +3343,7 @@ describe('ReactFlight', () => {
     const instance = mockConsoleLog.mock.calls[0][1].instance;
     expect(typeof Class).toBe('function');
     expect(Class.prototype.constructor).toBe(Class);
+    expect(Class.name).toBe('MyClassName');
     expect(instance instanceof Class).toBe(true);
     expect(Object.getPrototypeOf(instance)).toBe(Class.prototype);
     expect(instance.x).toBe(1);
diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js
index 1a5cee7ba7245..19a49dcd32b98 100644
--- a/packages/react-server/src/ReactFlightServer.js
+++ b/packages/react-server/src/ReactFlightServer.js
@@ -4848,9 +4848,18 @@ function renderDebugModel(
       return existingReference;
     }
 
+    // $FlowFixMe[method-unbinding]
+    const functionBody: string = Function.prototype.toString.call(value);
+
+    const name = value.name;
     const serializedValue = serializeEval(
-      // $FlowFixMe[method-unbinding]
-      '(' + Function.prototype.toString.call(value) + ')',
+      typeof name === 'string'
+        ? 'Object.defineProperty(' +
+            functionBody +
+            ',"name",{value:' +
+            JSON.stringify(name) +
+            '})'
+        : '(' + functionBody + ')',
     );
     request.pendingDebugChunks++;
     const id = request.nextChunkId++;