@react-devtools-plus/kit 0.9.3 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +146 -12
- package/dist/index.d.cts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +146 -12
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -105,9 +105,28 @@ function getFiberFromElement(element) {
|
|
|
105
105
|
//#endregion
|
|
106
106
|
//#region src/core/context/index.ts
|
|
107
107
|
/**
|
|
108
|
+
* Properties that can cause prototype pollution and should be filtered out
|
|
109
|
+
* SuperJSON will throw an error if these properties are present in the object
|
|
110
|
+
*/
|
|
111
|
+
const DANGEROUS_PROPERTIES$1 = new Set([
|
|
112
|
+
"constructor",
|
|
113
|
+
"__proto__",
|
|
114
|
+
"prototype"
|
|
115
|
+
]);
|
|
116
|
+
/**
|
|
117
|
+
* Check if a property key is safe to serialize (not a prototype pollution risk)
|
|
118
|
+
*/
|
|
119
|
+
function isSafePropertyKey$1(key) {
|
|
120
|
+
return !DANGEROUS_PROPERTIES$1.has(key);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
108
123
|
* Serialize a value into a displayable PropValue
|
|
124
|
+
* @param value - The value to serialize
|
|
125
|
+
* @param depth - Current recursion depth
|
|
126
|
+
* @param maxDepth - Maximum recursion depth
|
|
127
|
+
* @param context - Optional context to collect warnings about filtered properties
|
|
109
128
|
*/
|
|
110
|
-
function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
129
|
+
function serializeValue$1(value, depth = 0, maxDepth = 6, context) {
|
|
111
130
|
if (value === null) return {
|
|
112
131
|
type: "null",
|
|
113
132
|
value: "null"
|
|
@@ -150,7 +169,7 @@ function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
|
150
169
|
if (Array.isArray(value)) {
|
|
151
170
|
const children = {};
|
|
152
171
|
value.forEach((item, index) => {
|
|
153
|
-
children[String(index)] = serializeValue$1(item, depth + 1, maxDepth);
|
|
172
|
+
children[String(index)] = serializeValue$1(item, depth + 1, maxDepth, context);
|
|
154
173
|
});
|
|
155
174
|
return {
|
|
156
175
|
type: "array",
|
|
@@ -166,10 +185,13 @@ function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
|
166
185
|
value: `<${((_value$type = value.type) === null || _value$type === void 0 ? void 0 : _value$type.displayName) || ((_value$type2 = value.type) === null || _value$type2 === void 0 ? void 0 : _value$type2.name) || value.type || "Unknown"} />`
|
|
167
186
|
};
|
|
168
187
|
}
|
|
169
|
-
const
|
|
188
|
+
const allKeys = Object.keys(value);
|
|
189
|
+
const safeKeys = allKeys.filter(isSafePropertyKey$1);
|
|
190
|
+
const filteredKeys = allKeys.filter((key) => !isSafePropertyKey$1(key));
|
|
191
|
+
if (context && filteredKeys.length > 0) filteredKeys.forEach((key) => context.filteredProperties.add(key));
|
|
170
192
|
const children = {};
|
|
171
|
-
for (const key of
|
|
172
|
-
children[key] = serializeValue$1(value[key], depth + 1, maxDepth);
|
|
193
|
+
for (const key of safeKeys) try {
|
|
194
|
+
children[key] = serializeValue$1(value[key], depth + 1, maxDepth, context);
|
|
173
195
|
} catch (_unused) {
|
|
174
196
|
children[key] = {
|
|
175
197
|
type: "unknown",
|
|
@@ -179,7 +201,7 @@ function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
|
179
201
|
return {
|
|
180
202
|
type: "object",
|
|
181
203
|
value: `Object`,
|
|
182
|
-
preview:
|
|
204
|
+
preview: safeKeys.length > 0 ? `{${safeKeys.slice(0, 3).join(", ")}${safeKeys.length > 3 ? ", ..." : ""}}` : "{}",
|
|
183
205
|
children: Object.keys(children).length > 0 ? children : void 0
|
|
184
206
|
};
|
|
185
207
|
}
|
|
@@ -189,6 +211,23 @@ function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
|
189
211
|
};
|
|
190
212
|
}
|
|
191
213
|
/**
|
|
214
|
+
* Serialize a context value and collect any warnings
|
|
215
|
+
*/
|
|
216
|
+
function serializeContextValue(value) {
|
|
217
|
+
const context = { filteredProperties: /* @__PURE__ */ new Set() };
|
|
218
|
+
const propValue = serializeValue$1(value, 0, 6, context);
|
|
219
|
+
const warnings = [];
|
|
220
|
+
for (const property of context.filteredProperties) warnings.push({
|
|
221
|
+
type: "filtered_property",
|
|
222
|
+
property,
|
|
223
|
+
message: `Property "${property}" was hidden to prevent prototype pollution errors. This does not affect your application.`
|
|
224
|
+
});
|
|
225
|
+
return {
|
|
226
|
+
propValue,
|
|
227
|
+
warnings
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
192
231
|
* Get the display name of a Context
|
|
193
232
|
*/
|
|
194
233
|
function getContextDisplayName(fiber) {
|
|
@@ -264,10 +303,11 @@ function buildProviderInfo(fiber, visited) {
|
|
|
264
303
|
const consumers = [];
|
|
265
304
|
if (fiber.child) findConsumers(fiber.child, contextType, consumers, /* @__PURE__ */ new WeakSet());
|
|
266
305
|
const uniqueConsumers = consumers.filter((consumer, index, self) => index === self.findIndex((c) => c.id === consumer.id));
|
|
306
|
+
const { propValue, warnings } = serializeContextValue(getContextValue(fiber));
|
|
267
307
|
const info = {
|
|
268
308
|
id: getFiberId(fiber),
|
|
269
309
|
name: getContextDisplayName(fiber),
|
|
270
|
-
value:
|
|
310
|
+
value: propValue,
|
|
271
311
|
fiberId: getFiberId(fiber),
|
|
272
312
|
consumerCount: uniqueConsumers.length,
|
|
273
313
|
consumers: uniqueConsumers,
|
|
@@ -276,7 +316,8 @@ function buildProviderInfo(fiber, visited) {
|
|
|
276
316
|
fileName: fiber._debugSource.fileName,
|
|
277
317
|
lineNumber: fiber._debugSource.lineNumber,
|
|
278
318
|
columnNumber: fiber._debugSource.columnNumber
|
|
279
|
-
} : void 0
|
|
319
|
+
} : void 0,
|
|
320
|
+
warnings: warnings.length > 0 ? warnings : void 0
|
|
280
321
|
};
|
|
281
322
|
const findNestedProviders = (child) => {
|
|
282
323
|
var _child$type;
|
|
@@ -361,6 +402,21 @@ function getAllContexts(root) {
|
|
|
361
402
|
//#endregion
|
|
362
403
|
//#region src/core/fiber/details.ts
|
|
363
404
|
/**
|
|
405
|
+
* Properties that can cause prototype pollution and should be filtered out
|
|
406
|
+
* SuperJSON throws: "Detected property constructor. This is a property pollution risk"
|
|
407
|
+
*/
|
|
408
|
+
const DANGEROUS_PROPERTIES = new Set([
|
|
409
|
+
"constructor",
|
|
410
|
+
"__proto__",
|
|
411
|
+
"prototype"
|
|
412
|
+
]);
|
|
413
|
+
/**
|
|
414
|
+
* Check if a property key is safe to serialize (not a prototype pollution risk)
|
|
415
|
+
*/
|
|
416
|
+
function isSafePropertyKey(key) {
|
|
417
|
+
return !DANGEROUS_PROPERTIES.has(key);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
364
420
|
* Serialize a value into a displayable PropValue
|
|
365
421
|
*/
|
|
366
422
|
function serializeValue(value, depth = 0, maxDepth = 8) {
|
|
@@ -422,7 +478,7 @@ function serializeValue(value, depth = 0, maxDepth = 8) {
|
|
|
422
478
|
value: `<${((_value$type = value.type) === null || _value$type === void 0 ? void 0 : _value$type.displayName) || ((_value$type2 = value.type) === null || _value$type2 === void 0 ? void 0 : _value$type2.name) || value.type || "Unknown"} />`
|
|
423
479
|
};
|
|
424
480
|
}
|
|
425
|
-
const keys = Object.keys(value);
|
|
481
|
+
const keys = Object.keys(value).filter(isSafePropertyKey);
|
|
426
482
|
const children = {};
|
|
427
483
|
for (const key of keys) try {
|
|
428
484
|
children[key] = serializeValue(value[key], depth + 1, maxDepth);
|
|
@@ -1586,7 +1642,7 @@ function extractRouteFromElement(element, parentPath = "") {
|
|
|
1586
1642
|
return routeInfo;
|
|
1587
1643
|
}
|
|
1588
1644
|
/**
|
|
1589
|
-
* Extract routes from Routes component's children prop
|
|
1645
|
+
* Extract routes from Routes component's children prop (React Router v6)
|
|
1590
1646
|
*/
|
|
1591
1647
|
function extractRoutesFromProps(props) {
|
|
1592
1648
|
const routes = [];
|
|
@@ -1602,6 +1658,77 @@ function extractRoutesFromProps(props) {
|
|
|
1602
1658
|
return routes;
|
|
1603
1659
|
}
|
|
1604
1660
|
/**
|
|
1661
|
+
* Get component name from React Router v5 Route props
|
|
1662
|
+
*/
|
|
1663
|
+
function getV5ComponentName(props) {
|
|
1664
|
+
if (props.component) return props.component.name || props.component.displayName;
|
|
1665
|
+
if (props.render) return "render()";
|
|
1666
|
+
if (typeof props.children === "function") return "children()";
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Extract route info from a React Router v5 Route element (JSX props)
|
|
1670
|
+
*/
|
|
1671
|
+
function extractRouteFromElementV5(element, parentPath = "") {
|
|
1672
|
+
if (!element || !element.props) return null;
|
|
1673
|
+
const props = element.props;
|
|
1674
|
+
const path = props.path || "*";
|
|
1675
|
+
let fullPath = path;
|
|
1676
|
+
if (path !== "*" && !path.startsWith("/") && parentPath) fullPath = `${parentPath}/${path}`.replace(/\/+/g, "/");
|
|
1677
|
+
const params = extractParamsFromPath(path);
|
|
1678
|
+
const childRoutes = [];
|
|
1679
|
+
if (props.children && typeof props.children !== "function") {
|
|
1680
|
+
const children = Array.isArray(props.children) ? props.children : [props.children];
|
|
1681
|
+
for (const child of children) {
|
|
1682
|
+
var _child$type3, _child$type4;
|
|
1683
|
+
if (child && child.type && (child.type.name === "Route" || ((_child$type3 = child.type) === null || _child$type3 === void 0 ? void 0 : _child$type3.displayName) === "Route")) {
|
|
1684
|
+
const childRoute = extractRouteFromElementV5(child, fullPath);
|
|
1685
|
+
if (childRoute) childRoutes.push(childRoute);
|
|
1686
|
+
}
|
|
1687
|
+
if (child && child.type && (child.type.name === "Switch" || ((_child$type4 = child.type) === null || _child$type4 === void 0 ? void 0 : _child$type4.displayName) === "Switch")) {
|
|
1688
|
+
const switchChildren = extractRoutesFromSwitchProps(child.props, fullPath);
|
|
1689
|
+
childRoutes.push(...switchChildren);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
const hasChildren = childRoutes.length > 0;
|
|
1694
|
+
const routeInfo = {
|
|
1695
|
+
path: fullPath,
|
|
1696
|
+
element: getV5ComponentName(props),
|
|
1697
|
+
exact: props.exact === true,
|
|
1698
|
+
strict: props.strict === true,
|
|
1699
|
+
isLayout: hasChildren,
|
|
1700
|
+
isLazy: isLazyElement(props.component),
|
|
1701
|
+
params: params.length > 0 ? params : void 0
|
|
1702
|
+
};
|
|
1703
|
+
if (hasChildren) routeInfo.children = childRoutes;
|
|
1704
|
+
return routeInfo;
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Extract routes from Switch component's children prop (React Router v5)
|
|
1708
|
+
*/
|
|
1709
|
+
function extractRoutesFromSwitchProps(props, parentPath = "") {
|
|
1710
|
+
const routes = [];
|
|
1711
|
+
if (!(props === null || props === void 0 ? void 0 : props.children)) return routes;
|
|
1712
|
+
const children = Array.isArray(props.children) ? props.children : [props.children];
|
|
1713
|
+
for (const child of children) if (child && child.type) {
|
|
1714
|
+
const typeName = child.type.name || child.type.displayName;
|
|
1715
|
+
if (typeName === "Route") {
|
|
1716
|
+
const route = extractRouteFromElementV5(child, parentPath);
|
|
1717
|
+
if (route) routes.push(route);
|
|
1718
|
+
}
|
|
1719
|
+
if (typeName === "Redirect") {
|
|
1720
|
+
var _child$props, _child$props2, _child$props3;
|
|
1721
|
+
const redirectInfo = {
|
|
1722
|
+
path: ((_child$props = child.props) === null || _child$props === void 0 ? void 0 : _child$props.from) || "*",
|
|
1723
|
+
element: `Redirect → ${((_child$props2 = child.props) === null || _child$props2 === void 0 ? void 0 : _child$props2.to) || "unknown"}`,
|
|
1724
|
+
exact: ((_child$props3 = child.props) === null || _child$props3 === void 0 ? void 0 : _child$props3.exact) === true
|
|
1725
|
+
};
|
|
1726
|
+
routes.push(redirectInfo);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
return routes;
|
|
1730
|
+
}
|
|
1731
|
+
/**
|
|
1605
1732
|
* Extract route configuration from fiber tree
|
|
1606
1733
|
*/
|
|
1607
1734
|
function extractRoutesFromFiber(fiber) {
|
|
@@ -1636,7 +1763,7 @@ function extractRoutesFromFiber(fiber) {
|
|
|
1636
1763
|
return routes;
|
|
1637
1764
|
}
|
|
1638
1765
|
/**
|
|
1639
|
-
* Find Routes component and extract route configuration
|
|
1766
|
+
* Find Routes/Switch component and extract route configuration
|
|
1640
1767
|
*/
|
|
1641
1768
|
function findAndExtractRoutes(fiber) {
|
|
1642
1769
|
if (!fiber) return [];
|
|
@@ -1654,6 +1781,13 @@ function findAndExtractRoutes(fiber) {
|
|
|
1654
1781
|
return;
|
|
1655
1782
|
}
|
|
1656
1783
|
}
|
|
1784
|
+
if (name === "Switch") {
|
|
1785
|
+
const switchRoutes = extractRoutesFromSwitchProps(props);
|
|
1786
|
+
if (switchRoutes.length > 0) {
|
|
1787
|
+
routes = switchRoutes;
|
|
1788
|
+
return;
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1657
1791
|
if (name === "DataRoutes" || name === "RoutesRenderer") {
|
|
1658
1792
|
const fiberRoutes = extractRoutesFromFiber(node);
|
|
1659
1793
|
if (fiberRoutes.length > 0) routes.push(...fiberRoutes);
|
|
@@ -1769,7 +1903,7 @@ function detectRouterType(fiber) {
|
|
|
1769
1903
|
if (!node || visited.has(node)) return null;
|
|
1770
1904
|
visited.add(node);
|
|
1771
1905
|
const name = getDisplayName(node);
|
|
1772
|
-
if (name === "Router" || name === "BrowserRouter" || name === "HashRouter" || name === "MemoryRouter" || name === "Routes" || name === "Route") return "react-router";
|
|
1906
|
+
if (name === "Router" || name === "BrowserRouter" || name === "HashRouter" || name === "MemoryRouter" || name === "Routes" || name === "Switch" || name === "Route") return "react-router";
|
|
1773
1907
|
if (node.child) {
|
|
1774
1908
|
const result = traverse$1(node.child);
|
|
1775
1909
|
if (result) return result;
|
package/dist/index.d.cts
CHANGED
|
@@ -148,6 +148,16 @@ declare global {
|
|
|
148
148
|
}
|
|
149
149
|
//#endregion
|
|
150
150
|
//#region src/core/context/index.d.ts
|
|
151
|
+
/**
|
|
152
|
+
* Warning about filtered properties in context values
|
|
153
|
+
*/
|
|
154
|
+
interface ContextWarning {
|
|
155
|
+
type: 'filtered_property';
|
|
156
|
+
/** The property name that was filtered */
|
|
157
|
+
property: string;
|
|
158
|
+
/** Human-readable message */
|
|
159
|
+
message: string;
|
|
160
|
+
}
|
|
151
161
|
/**
|
|
152
162
|
* Information about a Context Provider
|
|
153
163
|
*/
|
|
@@ -171,6 +181,8 @@ interface ContextProviderInfo {
|
|
|
171
181
|
lineNumber: number;
|
|
172
182
|
columnNumber: number;
|
|
173
183
|
};
|
|
184
|
+
/** Warnings about the context value (e.g., filtered properties) */
|
|
185
|
+
warnings?: ContextWarning[];
|
|
174
186
|
}
|
|
175
187
|
/**
|
|
176
188
|
* Information about a Context Consumer
|
|
@@ -386,6 +398,10 @@ interface RouteInfo {
|
|
|
386
398
|
hasErrorBoundary?: boolean;
|
|
387
399
|
/** Dynamic segments in the path (e.g., :id, :userId) */
|
|
388
400
|
params?: string[];
|
|
401
|
+
/** Whether this route requires exact match (React Router v5) */
|
|
402
|
+
exact?: boolean;
|
|
403
|
+
/** Whether this route uses strict matching (React Router v5) */
|
|
404
|
+
strict?: boolean;
|
|
389
405
|
}
|
|
390
406
|
interface MatchedRoute {
|
|
391
407
|
path: string;
|
|
@@ -463,4 +479,4 @@ declare function createRpcServer<RemoteFunctions = Record<string, never>, LocalF
|
|
|
463
479
|
//#region src/messaging/presets/iframe/context.d.ts
|
|
464
480
|
declare function setIframeServerContext(iframe: HTMLIFrameElement | null): void;
|
|
465
481
|
//#endregion
|
|
466
|
-
export { ComponentDetails, ComponentTreeNode, ContextConsumerInfo, ContextProviderInfo, ContextTree, CreateRpcClientOptions, CreateRpcServerOptions, FiberNode, FiberRoot, HookInfo, HookStateInfo, MatchedRoute, NavigationEntry, PropValue, REACT_TAGS, ReactDevToolsHook, RenderedByInfo, RouteInfo, RouterState, SourceInfo, TIMELINE_LAYERS, type TimelineEvent, type TimelineLayer, type TimelineLayersState, ToggleInspectorOptions, TreeListener, addComponentEvent, addPerformanceEvent, buildTree, cleanupHighlight, clearFiberRegistry, clearNavigationHistory, clearOverrides, clearTimeline, createRpcClient, createRpcServer, getAllContexts, getAppFiberRoot, getComponentDetails, getComponentHookStates, getContextProviderInfo, getContextTree, getDisplayName, getFiberById, getFiberFromElement, getFiberId, getFiberRoot, getOverriddenContext, getOverriddenProp, getReactVersion, getRouterInfo, getRpcClient, getRpcServer, getTimelineState, hideHighlight, highlightNode, installReactHook, installTimelineEventListeners, isEditableProp, mergeClientRects, navigateTo, onInspectorSelect, onOpenInEditor, onTimelineEvent, onTreeUpdated, openInEditor, parseValue, rebuildTree, scrollToNode, setComponentProp, setContextValue, setContextValueAtPath, setContextValueFromJson, setFiberRoot, setHookState, setHookStateFromJson, setIframeServerContext, setRpcServerToGlobal, shouldIncludeFiber, showHighlight, toggleInspector, trackFiberPerformanceEnd, trackFiberPerformanceStart, updateTimelineState };
|
|
482
|
+
export { ComponentDetails, ComponentTreeNode, ContextConsumerInfo, ContextProviderInfo, ContextTree, ContextWarning, CreateRpcClientOptions, CreateRpcServerOptions, FiberNode, FiberRoot, HookInfo, HookStateInfo, MatchedRoute, NavigationEntry, PropValue, REACT_TAGS, ReactDevToolsHook, RenderedByInfo, RouteInfo, RouterState, SourceInfo, TIMELINE_LAYERS, type TimelineEvent, type TimelineLayer, type TimelineLayersState, ToggleInspectorOptions, TreeListener, addComponentEvent, addPerformanceEvent, buildTree, cleanupHighlight, clearFiberRegistry, clearNavigationHistory, clearOverrides, clearTimeline, createRpcClient, createRpcServer, getAllContexts, getAppFiberRoot, getComponentDetails, getComponentHookStates, getContextProviderInfo, getContextTree, getDisplayName, getFiberById, getFiberFromElement, getFiberId, getFiberRoot, getOverriddenContext, getOverriddenProp, getReactVersion, getRouterInfo, getRpcClient, getRpcServer, getTimelineState, hideHighlight, highlightNode, installReactHook, installTimelineEventListeners, isEditableProp, mergeClientRects, navigateTo, onInspectorSelect, onOpenInEditor, onTimelineEvent, onTreeUpdated, openInEditor, parseValue, rebuildTree, scrollToNode, setComponentProp, setContextValue, setContextValueAtPath, setContextValueFromJson, setFiberRoot, setHookState, setHookStateFromJson, setIframeServerContext, setRpcServerToGlobal, shouldIncludeFiber, showHighlight, toggleInspector, trackFiberPerformanceEnd, trackFiberPerformanceStart, updateTimelineState };
|
package/dist/index.d.ts
CHANGED
|
@@ -148,6 +148,16 @@ declare global {
|
|
|
148
148
|
}
|
|
149
149
|
//#endregion
|
|
150
150
|
//#region src/core/context/index.d.ts
|
|
151
|
+
/**
|
|
152
|
+
* Warning about filtered properties in context values
|
|
153
|
+
*/
|
|
154
|
+
interface ContextWarning {
|
|
155
|
+
type: 'filtered_property';
|
|
156
|
+
/** The property name that was filtered */
|
|
157
|
+
property: string;
|
|
158
|
+
/** Human-readable message */
|
|
159
|
+
message: string;
|
|
160
|
+
}
|
|
151
161
|
/**
|
|
152
162
|
* Information about a Context Provider
|
|
153
163
|
*/
|
|
@@ -171,6 +181,8 @@ interface ContextProviderInfo {
|
|
|
171
181
|
lineNumber: number;
|
|
172
182
|
columnNumber: number;
|
|
173
183
|
};
|
|
184
|
+
/** Warnings about the context value (e.g., filtered properties) */
|
|
185
|
+
warnings?: ContextWarning[];
|
|
174
186
|
}
|
|
175
187
|
/**
|
|
176
188
|
* Information about a Context Consumer
|
|
@@ -386,6 +398,10 @@ interface RouteInfo {
|
|
|
386
398
|
hasErrorBoundary?: boolean;
|
|
387
399
|
/** Dynamic segments in the path (e.g., :id, :userId) */
|
|
388
400
|
params?: string[];
|
|
401
|
+
/** Whether this route requires exact match (React Router v5) */
|
|
402
|
+
exact?: boolean;
|
|
403
|
+
/** Whether this route uses strict matching (React Router v5) */
|
|
404
|
+
strict?: boolean;
|
|
389
405
|
}
|
|
390
406
|
interface MatchedRoute {
|
|
391
407
|
path: string;
|
|
@@ -463,4 +479,4 @@ declare function createRpcServer<RemoteFunctions = Record<string, never>, LocalF
|
|
|
463
479
|
//#region src/messaging/presets/iframe/context.d.ts
|
|
464
480
|
declare function setIframeServerContext(iframe: HTMLIFrameElement | null): void;
|
|
465
481
|
//#endregion
|
|
466
|
-
export { ComponentDetails, ComponentTreeNode, ContextConsumerInfo, ContextProviderInfo, ContextTree, CreateRpcClientOptions, CreateRpcServerOptions, FiberNode, FiberRoot, HookInfo, HookStateInfo, MatchedRoute, NavigationEntry, PropValue, REACT_TAGS, ReactDevToolsHook, RenderedByInfo, RouteInfo, RouterState, SourceInfo, TIMELINE_LAYERS, type TimelineEvent, type TimelineLayer, type TimelineLayersState, ToggleInspectorOptions, TreeListener, addComponentEvent, addPerformanceEvent, buildTree, cleanupHighlight, clearFiberRegistry, clearNavigationHistory, clearOverrides, clearTimeline, createRpcClient, createRpcServer, getAllContexts, getAppFiberRoot, getComponentDetails, getComponentHookStates, getContextProviderInfo, getContextTree, getDisplayName, getFiberById, getFiberFromElement, getFiberId, getFiberRoot, getOverriddenContext, getOverriddenProp, getReactVersion, getRouterInfo, getRpcClient, getRpcServer, getTimelineState, hideHighlight, highlightNode, installReactHook, installTimelineEventListeners, isEditableProp, mergeClientRects, navigateTo, onInspectorSelect, onOpenInEditor, onTimelineEvent, onTreeUpdated, openInEditor, parseValue, rebuildTree, scrollToNode, setComponentProp, setContextValue, setContextValueAtPath, setContextValueFromJson, setFiberRoot, setHookState, setHookStateFromJson, setIframeServerContext, setRpcServerToGlobal, shouldIncludeFiber, showHighlight, toggleInspector, trackFiberPerformanceEnd, trackFiberPerformanceStart, updateTimelineState };
|
|
482
|
+
export { ComponentDetails, ComponentTreeNode, ContextConsumerInfo, ContextProviderInfo, ContextTree, ContextWarning, CreateRpcClientOptions, CreateRpcServerOptions, FiberNode, FiberRoot, HookInfo, HookStateInfo, MatchedRoute, NavigationEntry, PropValue, REACT_TAGS, ReactDevToolsHook, RenderedByInfo, RouteInfo, RouterState, SourceInfo, TIMELINE_LAYERS, type TimelineEvent, type TimelineLayer, type TimelineLayersState, ToggleInspectorOptions, TreeListener, addComponentEvent, addPerformanceEvent, buildTree, cleanupHighlight, clearFiberRegistry, clearNavigationHistory, clearOverrides, clearTimeline, createRpcClient, createRpcServer, getAllContexts, getAppFiberRoot, getComponentDetails, getComponentHookStates, getContextProviderInfo, getContextTree, getDisplayName, getFiberById, getFiberFromElement, getFiberId, getFiberRoot, getOverriddenContext, getOverriddenProp, getReactVersion, getRouterInfo, getRpcClient, getRpcServer, getTimelineState, hideHighlight, highlightNode, installReactHook, installTimelineEventListeners, isEditableProp, mergeClientRects, navigateTo, onInspectorSelect, onOpenInEditor, onTimelineEvent, onTreeUpdated, openInEditor, parseValue, rebuildTree, scrollToNode, setComponentProp, setContextValue, setContextValueAtPath, setContextValueFromJson, setFiberRoot, setHookState, setHookStateFromJson, setIframeServerContext, setRpcServerToGlobal, shouldIncludeFiber, showHighlight, toggleInspector, trackFiberPerformanceEnd, trackFiberPerformanceStart, updateTimelineState };
|
package/dist/index.js
CHANGED
|
@@ -81,9 +81,28 @@ function getFiberFromElement(element) {
|
|
|
81
81
|
//#endregion
|
|
82
82
|
//#region src/core/context/index.ts
|
|
83
83
|
/**
|
|
84
|
+
* Properties that can cause prototype pollution and should be filtered out
|
|
85
|
+
* SuperJSON will throw an error if these properties are present in the object
|
|
86
|
+
*/
|
|
87
|
+
const DANGEROUS_PROPERTIES$1 = new Set([
|
|
88
|
+
"constructor",
|
|
89
|
+
"__proto__",
|
|
90
|
+
"prototype"
|
|
91
|
+
]);
|
|
92
|
+
/**
|
|
93
|
+
* Check if a property key is safe to serialize (not a prototype pollution risk)
|
|
94
|
+
*/
|
|
95
|
+
function isSafePropertyKey$1(key) {
|
|
96
|
+
return !DANGEROUS_PROPERTIES$1.has(key);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
84
99
|
* Serialize a value into a displayable PropValue
|
|
100
|
+
* @param value - The value to serialize
|
|
101
|
+
* @param depth - Current recursion depth
|
|
102
|
+
* @param maxDepth - Maximum recursion depth
|
|
103
|
+
* @param context - Optional context to collect warnings about filtered properties
|
|
85
104
|
*/
|
|
86
|
-
function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
105
|
+
function serializeValue$1(value, depth = 0, maxDepth = 6, context) {
|
|
87
106
|
if (value === null) return {
|
|
88
107
|
type: "null",
|
|
89
108
|
value: "null"
|
|
@@ -126,7 +145,7 @@ function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
|
126
145
|
if (Array.isArray(value)) {
|
|
127
146
|
const children = {};
|
|
128
147
|
value.forEach((item, index) => {
|
|
129
|
-
children[String(index)] = serializeValue$1(item, depth + 1, maxDepth);
|
|
148
|
+
children[String(index)] = serializeValue$1(item, depth + 1, maxDepth, context);
|
|
130
149
|
});
|
|
131
150
|
return {
|
|
132
151
|
type: "array",
|
|
@@ -142,10 +161,13 @@ function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
|
142
161
|
value: `<${((_value$type = value.type) === null || _value$type === void 0 ? void 0 : _value$type.displayName) || ((_value$type2 = value.type) === null || _value$type2 === void 0 ? void 0 : _value$type2.name) || value.type || "Unknown"} />`
|
|
143
162
|
};
|
|
144
163
|
}
|
|
145
|
-
const
|
|
164
|
+
const allKeys = Object.keys(value);
|
|
165
|
+
const safeKeys = allKeys.filter(isSafePropertyKey$1);
|
|
166
|
+
const filteredKeys = allKeys.filter((key) => !isSafePropertyKey$1(key));
|
|
167
|
+
if (context && filteredKeys.length > 0) filteredKeys.forEach((key) => context.filteredProperties.add(key));
|
|
146
168
|
const children = {};
|
|
147
|
-
for (const key of
|
|
148
|
-
children[key] = serializeValue$1(value[key], depth + 1, maxDepth);
|
|
169
|
+
for (const key of safeKeys) try {
|
|
170
|
+
children[key] = serializeValue$1(value[key], depth + 1, maxDepth, context);
|
|
149
171
|
} catch (_unused) {
|
|
150
172
|
children[key] = {
|
|
151
173
|
type: "unknown",
|
|
@@ -155,7 +177,7 @@ function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
|
155
177
|
return {
|
|
156
178
|
type: "object",
|
|
157
179
|
value: `Object`,
|
|
158
|
-
preview:
|
|
180
|
+
preview: safeKeys.length > 0 ? `{${safeKeys.slice(0, 3).join(", ")}${safeKeys.length > 3 ? ", ..." : ""}}` : "{}",
|
|
159
181
|
children: Object.keys(children).length > 0 ? children : void 0
|
|
160
182
|
};
|
|
161
183
|
}
|
|
@@ -165,6 +187,23 @@ function serializeValue$1(value, depth = 0, maxDepth = 6) {
|
|
|
165
187
|
};
|
|
166
188
|
}
|
|
167
189
|
/**
|
|
190
|
+
* Serialize a context value and collect any warnings
|
|
191
|
+
*/
|
|
192
|
+
function serializeContextValue(value) {
|
|
193
|
+
const context = { filteredProperties: /* @__PURE__ */ new Set() };
|
|
194
|
+
const propValue = serializeValue$1(value, 0, 6, context);
|
|
195
|
+
const warnings = [];
|
|
196
|
+
for (const property of context.filteredProperties) warnings.push({
|
|
197
|
+
type: "filtered_property",
|
|
198
|
+
property,
|
|
199
|
+
message: `Property "${property}" was hidden to prevent prototype pollution errors. This does not affect your application.`
|
|
200
|
+
});
|
|
201
|
+
return {
|
|
202
|
+
propValue,
|
|
203
|
+
warnings
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
168
207
|
* Get the display name of a Context
|
|
169
208
|
*/
|
|
170
209
|
function getContextDisplayName(fiber) {
|
|
@@ -240,10 +279,11 @@ function buildProviderInfo(fiber, visited) {
|
|
|
240
279
|
const consumers = [];
|
|
241
280
|
if (fiber.child) findConsumers(fiber.child, contextType, consumers, /* @__PURE__ */ new WeakSet());
|
|
242
281
|
const uniqueConsumers = consumers.filter((consumer, index, self) => index === self.findIndex((c) => c.id === consumer.id));
|
|
282
|
+
const { propValue, warnings } = serializeContextValue(getContextValue(fiber));
|
|
243
283
|
const info = {
|
|
244
284
|
id: getFiberId(fiber),
|
|
245
285
|
name: getContextDisplayName(fiber),
|
|
246
|
-
value:
|
|
286
|
+
value: propValue,
|
|
247
287
|
fiberId: getFiberId(fiber),
|
|
248
288
|
consumerCount: uniqueConsumers.length,
|
|
249
289
|
consumers: uniqueConsumers,
|
|
@@ -252,7 +292,8 @@ function buildProviderInfo(fiber, visited) {
|
|
|
252
292
|
fileName: fiber._debugSource.fileName,
|
|
253
293
|
lineNumber: fiber._debugSource.lineNumber,
|
|
254
294
|
columnNumber: fiber._debugSource.columnNumber
|
|
255
|
-
} : void 0
|
|
295
|
+
} : void 0,
|
|
296
|
+
warnings: warnings.length > 0 ? warnings : void 0
|
|
256
297
|
};
|
|
257
298
|
const findNestedProviders = (child) => {
|
|
258
299
|
var _child$type;
|
|
@@ -337,6 +378,21 @@ function getAllContexts(root) {
|
|
|
337
378
|
//#endregion
|
|
338
379
|
//#region src/core/fiber/details.ts
|
|
339
380
|
/**
|
|
381
|
+
* Properties that can cause prototype pollution and should be filtered out
|
|
382
|
+
* SuperJSON throws: "Detected property constructor. This is a property pollution risk"
|
|
383
|
+
*/
|
|
384
|
+
const DANGEROUS_PROPERTIES = new Set([
|
|
385
|
+
"constructor",
|
|
386
|
+
"__proto__",
|
|
387
|
+
"prototype"
|
|
388
|
+
]);
|
|
389
|
+
/**
|
|
390
|
+
* Check if a property key is safe to serialize (not a prototype pollution risk)
|
|
391
|
+
*/
|
|
392
|
+
function isSafePropertyKey(key) {
|
|
393
|
+
return !DANGEROUS_PROPERTIES.has(key);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
340
396
|
* Serialize a value into a displayable PropValue
|
|
341
397
|
*/
|
|
342
398
|
function serializeValue(value, depth = 0, maxDepth = 8) {
|
|
@@ -398,7 +454,7 @@ function serializeValue(value, depth = 0, maxDepth = 8) {
|
|
|
398
454
|
value: `<${((_value$type = value.type) === null || _value$type === void 0 ? void 0 : _value$type.displayName) || ((_value$type2 = value.type) === null || _value$type2 === void 0 ? void 0 : _value$type2.name) || value.type || "Unknown"} />`
|
|
399
455
|
};
|
|
400
456
|
}
|
|
401
|
-
const keys = Object.keys(value);
|
|
457
|
+
const keys = Object.keys(value).filter(isSafePropertyKey);
|
|
402
458
|
const children = {};
|
|
403
459
|
for (const key of keys) try {
|
|
404
460
|
children[key] = serializeValue(value[key], depth + 1, maxDepth);
|
|
@@ -1562,7 +1618,7 @@ function extractRouteFromElement(element, parentPath = "") {
|
|
|
1562
1618
|
return routeInfo;
|
|
1563
1619
|
}
|
|
1564
1620
|
/**
|
|
1565
|
-
* Extract routes from Routes component's children prop
|
|
1621
|
+
* Extract routes from Routes component's children prop (React Router v6)
|
|
1566
1622
|
*/
|
|
1567
1623
|
function extractRoutesFromProps(props) {
|
|
1568
1624
|
const routes = [];
|
|
@@ -1578,6 +1634,77 @@ function extractRoutesFromProps(props) {
|
|
|
1578
1634
|
return routes;
|
|
1579
1635
|
}
|
|
1580
1636
|
/**
|
|
1637
|
+
* Get component name from React Router v5 Route props
|
|
1638
|
+
*/
|
|
1639
|
+
function getV5ComponentName(props) {
|
|
1640
|
+
if (props.component) return props.component.name || props.component.displayName;
|
|
1641
|
+
if (props.render) return "render()";
|
|
1642
|
+
if (typeof props.children === "function") return "children()";
|
|
1643
|
+
}
|
|
1644
|
+
/**
|
|
1645
|
+
* Extract route info from a React Router v5 Route element (JSX props)
|
|
1646
|
+
*/
|
|
1647
|
+
function extractRouteFromElementV5(element, parentPath = "") {
|
|
1648
|
+
if (!element || !element.props) return null;
|
|
1649
|
+
const props = element.props;
|
|
1650
|
+
const path = props.path || "*";
|
|
1651
|
+
let fullPath = path;
|
|
1652
|
+
if (path !== "*" && !path.startsWith("/") && parentPath) fullPath = `${parentPath}/${path}`.replace(/\/+/g, "/");
|
|
1653
|
+
const params = extractParamsFromPath(path);
|
|
1654
|
+
const childRoutes = [];
|
|
1655
|
+
if (props.children && typeof props.children !== "function") {
|
|
1656
|
+
const children = Array.isArray(props.children) ? props.children : [props.children];
|
|
1657
|
+
for (const child of children) {
|
|
1658
|
+
var _child$type3, _child$type4;
|
|
1659
|
+
if (child && child.type && (child.type.name === "Route" || ((_child$type3 = child.type) === null || _child$type3 === void 0 ? void 0 : _child$type3.displayName) === "Route")) {
|
|
1660
|
+
const childRoute = extractRouteFromElementV5(child, fullPath);
|
|
1661
|
+
if (childRoute) childRoutes.push(childRoute);
|
|
1662
|
+
}
|
|
1663
|
+
if (child && child.type && (child.type.name === "Switch" || ((_child$type4 = child.type) === null || _child$type4 === void 0 ? void 0 : _child$type4.displayName) === "Switch")) {
|
|
1664
|
+
const switchChildren = extractRoutesFromSwitchProps(child.props, fullPath);
|
|
1665
|
+
childRoutes.push(...switchChildren);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
const hasChildren = childRoutes.length > 0;
|
|
1670
|
+
const routeInfo = {
|
|
1671
|
+
path: fullPath,
|
|
1672
|
+
element: getV5ComponentName(props),
|
|
1673
|
+
exact: props.exact === true,
|
|
1674
|
+
strict: props.strict === true,
|
|
1675
|
+
isLayout: hasChildren,
|
|
1676
|
+
isLazy: isLazyElement(props.component),
|
|
1677
|
+
params: params.length > 0 ? params : void 0
|
|
1678
|
+
};
|
|
1679
|
+
if (hasChildren) routeInfo.children = childRoutes;
|
|
1680
|
+
return routeInfo;
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* Extract routes from Switch component's children prop (React Router v5)
|
|
1684
|
+
*/
|
|
1685
|
+
function extractRoutesFromSwitchProps(props, parentPath = "") {
|
|
1686
|
+
const routes = [];
|
|
1687
|
+
if (!(props === null || props === void 0 ? void 0 : props.children)) return routes;
|
|
1688
|
+
const children = Array.isArray(props.children) ? props.children : [props.children];
|
|
1689
|
+
for (const child of children) if (child && child.type) {
|
|
1690
|
+
const typeName = child.type.name || child.type.displayName;
|
|
1691
|
+
if (typeName === "Route") {
|
|
1692
|
+
const route = extractRouteFromElementV5(child, parentPath);
|
|
1693
|
+
if (route) routes.push(route);
|
|
1694
|
+
}
|
|
1695
|
+
if (typeName === "Redirect") {
|
|
1696
|
+
var _child$props, _child$props2, _child$props3;
|
|
1697
|
+
const redirectInfo = {
|
|
1698
|
+
path: ((_child$props = child.props) === null || _child$props === void 0 ? void 0 : _child$props.from) || "*",
|
|
1699
|
+
element: `Redirect → ${((_child$props2 = child.props) === null || _child$props2 === void 0 ? void 0 : _child$props2.to) || "unknown"}`,
|
|
1700
|
+
exact: ((_child$props3 = child.props) === null || _child$props3 === void 0 ? void 0 : _child$props3.exact) === true
|
|
1701
|
+
};
|
|
1702
|
+
routes.push(redirectInfo);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
return routes;
|
|
1706
|
+
}
|
|
1707
|
+
/**
|
|
1581
1708
|
* Extract route configuration from fiber tree
|
|
1582
1709
|
*/
|
|
1583
1710
|
function extractRoutesFromFiber(fiber) {
|
|
@@ -1612,7 +1739,7 @@ function extractRoutesFromFiber(fiber) {
|
|
|
1612
1739
|
return routes;
|
|
1613
1740
|
}
|
|
1614
1741
|
/**
|
|
1615
|
-
* Find Routes component and extract route configuration
|
|
1742
|
+
* Find Routes/Switch component and extract route configuration
|
|
1616
1743
|
*/
|
|
1617
1744
|
function findAndExtractRoutes(fiber) {
|
|
1618
1745
|
if (!fiber) return [];
|
|
@@ -1630,6 +1757,13 @@ function findAndExtractRoutes(fiber) {
|
|
|
1630
1757
|
return;
|
|
1631
1758
|
}
|
|
1632
1759
|
}
|
|
1760
|
+
if (name === "Switch") {
|
|
1761
|
+
const switchRoutes = extractRoutesFromSwitchProps(props);
|
|
1762
|
+
if (switchRoutes.length > 0) {
|
|
1763
|
+
routes = switchRoutes;
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1633
1767
|
if (name === "DataRoutes" || name === "RoutesRenderer") {
|
|
1634
1768
|
const fiberRoutes = extractRoutesFromFiber(node);
|
|
1635
1769
|
if (fiberRoutes.length > 0) routes.push(...fiberRoutes);
|
|
@@ -1745,7 +1879,7 @@ function detectRouterType(fiber) {
|
|
|
1745
1879
|
if (!node || visited.has(node)) return null;
|
|
1746
1880
|
visited.add(node);
|
|
1747
1881
|
const name = getDisplayName(node);
|
|
1748
|
-
if (name === "Router" || name === "BrowserRouter" || name === "HashRouter" || name === "MemoryRouter" || name === "Routes" || name === "Route") return "react-router";
|
|
1882
|
+
if (name === "Router" || name === "BrowserRouter" || name === "HashRouter" || name === "MemoryRouter" || name === "Routes" || name === "Switch" || name === "Route") return "react-router";
|
|
1749
1883
|
if (node.child) {
|
|
1750
1884
|
const result = traverse$1(node.child);
|
|
1751
1885
|
if (result) return result;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-devtools-plus/kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.5",
|
|
5
5
|
"author": "wzc520pyfm",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"mitt": "^3.0.1",
|
|
28
28
|
"perfect-debounce": "^2.0.0",
|
|
29
29
|
"superjson": "^2.2.2",
|
|
30
|
-
"@react-devtools-plus/shared": "^0.9.
|
|
30
|
+
"@react-devtools-plus/shared": "^0.9.5"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^24.7.2",
|