bippy 0.6.1-dev.b88fcb4 → 0.6.1-dev.f9e6c65

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.
Files changed (45) hide show
  1. package/README.md +159 -487
  2. package/dist/core.cjs +1 -1
  3. package/dist/core.d.cts +8 -54
  4. package/dist/core.d.ts +8 -54
  5. package/dist/core.js +1 -1
  6. package/dist/core2.cjs +1 -1
  7. package/dist/core2.d.cts +3 -3
  8. package/dist/core2.d.ts +3 -3
  9. package/dist/core2.js +1 -1
  10. package/dist/errors.d.cts +2 -57
  11. package/dist/errors.d.ts +2 -57
  12. package/dist/index.cjs +1 -1
  13. package/dist/index.d.cts +6 -3
  14. package/dist/index.d.ts +6 -3
  15. package/dist/index.js +1 -1
  16. package/dist/install-hook-only.cjs +1 -1
  17. package/dist/install-hook-only.js +1 -1
  18. package/dist/rdt-hook.cjs +1 -1
  19. package/dist/rdt-hook.js +1 -1
  20. package/dist/source.cjs +12 -13
  21. package/dist/source.d.cts +77 -78
  22. package/dist/source.d.ts +77 -78
  23. package/dist/source.js +12 -13
  24. package/package.json +6 -3
  25. package/src/core.ts +101 -530
  26. package/src/errors.ts +0 -65
  27. package/src/index.ts +1 -0
  28. package/src/install-hook-only.ts +2 -2
  29. package/src/rdt-hook.ts +30 -43
  30. package/src/react-internals/generated/react-work-tags.ts +6 -2
  31. package/src/react-internals/index.ts +4 -4
  32. package/src/react-internals/semver.ts +2 -0
  33. package/src/react-internals/types.ts +0 -83
  34. package/src/react.ts +76 -0
  35. package/src/source/get-display-name-from-source.ts +44 -40
  36. package/src/source/get-source.ts +40 -24
  37. package/src/source/index.ts +2 -0
  38. package/src/source/inspect-hooks.ts +70 -91
  39. package/src/source/owner-stack.ts +60 -89
  40. package/src/source/parse-hook-names.ts +14 -53
  41. package/src/source/parse-stack.ts +14 -31
  42. package/src/source/renderer-dispatchers.ts +30 -0
  43. package/src/source/symbolication.ts +312 -111
  44. package/dist/index.iife.js +0 -9
  45. package/dist/install-hook-only.iife.js +0 -9
@@ -1,4 +1,5 @@
1
1
  import type { Fiber } from "../react-internals/index.js";
2
+ import { getDisplayName } from "../core.js";
2
3
 
3
4
  import type { FiberSource } from "./types.js";
4
5
  import {
@@ -12,8 +13,13 @@ import {
12
13
  } from "./constants.js";
13
14
  import { getDefinitionFrameFromOwnedChild, getParentStack, hasDebugStack } from "./owner-stack.js";
14
15
  import { parseDebugStack } from "./parse-debug-stack.js";
15
- import { StackFrame } from "./parse-stack.js";
16
- import { symbolicateStack } from "./symbolication.js";
16
+ import { parseStack, type StackFrame } from "./parse-stack.js";
17
+ import {
18
+ getSourceFromSourceMapByFunctionName,
19
+ getSourceMap,
20
+ symbolicateStack,
21
+ type SourceFetch,
22
+ } from "./symbolication.js";
17
23
 
18
24
  export const hasDebugSource = (
19
25
  fiber: Fiber,
@@ -26,10 +32,8 @@ export const hasDebugSource = (
26
32
  }
27
33
  return (
28
34
  typeof debugSource === "object" &&
29
- debugSource !== null &&
30
- "fileName" in debugSource &&
31
35
  typeof debugSource.fileName === "string" &&
32
- "lineNumber" in debugSource &&
36
+ debugSource.fileName !== "(native)" &&
33
37
  typeof debugSource.lineNumber === "number"
34
38
  );
35
39
  };
@@ -63,6 +67,30 @@ const getUsageFrameFromDebugStack = (fiber: Fiber): StackFrame | null => {
63
67
  return null;
64
68
  };
65
69
 
70
+ const getSourceByComponentName = async (
71
+ fiber: Fiber,
72
+ cache: boolean,
73
+ fetchFn: SourceFetch | undefined,
74
+ ): Promise<FiberSource | null> => {
75
+ const functionName = getDisplayName(fiber.type);
76
+ if (!functionName) return null;
77
+
78
+ const runtimeStackFrames = parseStack(new Error().stack ?? "");
79
+ const visitedFileNames = new Set<string>();
80
+ for (const stackFrame of runtimeStackFrames) {
81
+ const fileName = stackFrame.fileName;
82
+ if (!fileName || visitedFileNames.has(fileName)) {
83
+ continue;
84
+ }
85
+ visitedFileNames.add(fileName);
86
+ const sourceMap = await getSourceMap(fileName, cache, fetchFn);
87
+ if (!sourceMap) continue;
88
+ const source = getSourceFromSourceMapByFunctionName(sourceMap, functionName);
89
+ if (source && !source.isIgnoreListed) return toFiberSource(source);
90
+ }
91
+ return null;
92
+ };
93
+
66
94
  /**
67
95
  * Returns the source of where the component is used. Available only in dev, for composite {@link Fiber}s.
68
96
  *
@@ -92,11 +120,10 @@ const getUsageFrameFromDebugStack = (fiber: Fiber): StackFrame | null => {
92
120
  export const getSource = async (
93
121
  fiber: Fiber,
94
122
  cache = true,
95
- fetchFn?: (url: string) => Promise<Response>,
123
+ fetchFn?: SourceFetch,
96
124
  ): Promise<FiberSource | null> => {
97
125
  if (hasDebugSource(fiber)) {
98
- const debugSource = fiber._debugSource;
99
- return debugSource || null;
126
+ return fiber._debugSource;
100
127
  }
101
128
 
102
129
  const debugStackFrame =
@@ -115,16 +142,11 @@ export const getSource = async (
115
142
  return toFiberSource(stackFrame);
116
143
  }
117
144
  }
118
- return null;
145
+ return getSourceByComponentName(fiber, cache, fetchFn);
119
146
  };
120
147
 
121
148
  const getPathSegmentCount = (path: string): number => path.split("/").filter(Boolean).length;
122
149
 
123
- const getFirstPathSegment = (path: string): string | null => {
124
- const segments = path.split("/").filter(Boolean);
125
- return segments[0] ?? null;
126
- };
127
-
128
150
  const stripSingleBasePathPrefix = (path: string): string => {
129
151
  const firstSlashIndex = path.indexOf("/", 1);
130
152
  if (firstSlashIndex === -1) {
@@ -141,15 +163,12 @@ const stripSingleBasePathPrefix = (path: string): string => {
141
163
  return path;
142
164
  }
143
165
 
144
- if (getPathSegmentCount(remainderPath) < 2) {
145
- return path;
146
- }
147
-
148
- const firstRemainderSegment = getFirstPathSegment(remainderPath);
149
- if (!firstRemainderSegment) {
166
+ const remainderSegments = remainderPath.split("/").filter(Boolean);
167
+ if (remainderSegments.length < 2) {
150
168
  return path;
151
169
  }
152
170
 
171
+ const firstRemainderSegment = remainderSegments[0];
153
172
  if (firstRemainderSegment.startsWith("@")) {
154
173
  return path;
155
174
  }
@@ -180,9 +199,6 @@ export const normalizeFileName = (fileName: string): string => {
180
199
  const parsedUrl = new URL(normalizedFileName);
181
200
  normalizedFileName = parsedUrl.pathname;
182
201
  } catch {}
183
- }
184
-
185
- if (isHttpUrl) {
186
202
  normalizedFileName = stripSingleBasePathPrefix(normalizedFileName);
187
203
  }
188
204
 
@@ -215,7 +231,7 @@ export const normalizeFileName = (fileName: string): string => {
215
231
  }
216
232
  }
217
233
 
218
- if (!isWindowsDrivePath && SCHEME_REGEX.test(normalizedFileName)) {
234
+ if (!isWindowsDrivePath) {
219
235
  const schemeMatch = normalizedFileName.match(SCHEME_REGEX);
220
236
  if (schemeMatch) {
221
237
  normalizedFileName = normalizedFileName.slice(schemeMatch[0].length);
@@ -1,7 +1,9 @@
1
1
  export { formatOwnerStack, getOwnerStack, getParentStack, hasDebugStack } from "./owner-stack.js";
2
2
  export { getSource, isSourceFile, normalizeFileName } from "./get-source.js";
3
3
  export {
4
+ getSourceContentFromSourceMap,
4
5
  getSourceFromSourceMap,
6
+ getSourceFromSourceMapByFunctionName,
5
7
  getSourceMap,
6
8
  symbolicateStack,
7
9
  type DecodedSourceMapSection,
@@ -12,7 +12,11 @@ import {
12
12
  } from "../errors.js";
13
13
  import { getReactWorkTagsForFiber } from "../react-internals/index.js";
14
14
  import { parseStack, type StackFrame } from "./parse-stack.js";
15
- import { getRDTHook, _renderers } from "../rdt-hook.js";
15
+ import {
16
+ getRendererDispatcherRefs,
17
+ readDispatcher,
18
+ writeDispatcher,
19
+ } from "./renderer-dispatchers.js";
16
20
 
17
21
  const REACT_CONTEXT_TYPE = Symbol.for("react.context");
18
22
  const REACT_MEMO_CACHE_SENTINEL = Symbol.for("react.memo_cache_sentinel");
@@ -77,7 +81,7 @@ let currentThenableIndex = 0;
77
81
  let currentThenableState: unknown[] | null = null;
78
82
 
79
83
  const SuspenseException: unknown = new Error(
80
- "Suspense Exception: This is not a real error! It's an implementation detail of `use` to interrupt the current render.",
84
+ "Suspense interrupted this render. This error is an internal implementation detail of `use`.",
81
85
  );
82
86
 
83
87
  const parseErrorStack = (error: Error): StackFrame[] =>
@@ -89,28 +93,31 @@ const nextHook = (): MemoizedState | null => {
89
93
  return hook;
90
94
  };
91
95
 
92
- const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
93
- typeof value === "object" && value !== null;
94
-
95
96
  const isInspectableThenable = (value: unknown): value is InspectableThenable =>
96
- isObjectRecord(value) && typeof value.then === "function";
97
+ typeof value === "object" &&
98
+ value !== null &&
99
+ "then" in value &&
100
+ typeof value.then === "function";
97
101
 
98
102
  const isInspectableRef = (value: unknown): value is InspectableRef =>
99
- isObjectRecord(value) && "current" in value;
103
+ typeof value === "object" && value !== null && "current" in value;
100
104
 
101
105
  const isReactContext = (value: unknown): value is ReactContext<unknown> =>
102
- isObjectRecord(value) && "_currentValue" in value;
106
+ typeof value === "object" && value !== null && "_currentValue" in value;
103
107
 
104
108
  const isContextDependency = (value: unknown): value is ContextDependency<unknown> =>
105
- isObjectRecord(value) && "context" in value && "next" in value;
109
+ typeof value === "object" && value !== null && "context" in value && "next" in value;
106
110
 
107
111
  const isForwardRefRenderType = (value: unknown): value is ForwardRefRenderType =>
108
- isObjectRecord(value) && typeof value.render === "function";
112
+ typeof value === "object" &&
113
+ value !== null &&
114
+ "render" in value &&
115
+ typeof value.render === "function";
109
116
 
110
117
  const readContext = (context: InspectableReactContext): unknown => {
111
118
  if (currentFiber === null) return context._currentValue;
112
119
  if (currentContextDependency === null) {
113
- throw new BippyHookInspectionError("Context reads do not line up with context dependencies.");
120
+ throw new BippyHookInspectionError("Context reads don’t match context dependencies.");
114
121
  }
115
122
  if (Object.hasOwn(currentContextDependency, "memoizedValue")) {
116
123
  const value = currentContextDependency.memoizedValue;
@@ -120,27 +127,6 @@ const readContext = (context: InspectableReactContext): unknown => {
120
127
  return context._currentValue;
121
128
  };
122
129
 
123
- const getDispatcherRef = (): RendererDispatcherRef | null => {
124
- const rdtHook = getRDTHook();
125
- const allRenderers = [..._renderers, ...rdtHook.renderers.values()];
126
- for (const renderer of allRenderers) {
127
- const ref = renderer.currentDispatcherRef;
128
- if (ref) return ref;
129
- }
130
- return null;
131
- };
132
-
133
- const getDispatcherFromRef = (ref: RendererDispatcherRef): unknown =>
134
- "H" in ref ? ref.H : ref.current;
135
-
136
- const setDispatcherOnRef = (ref: RendererDispatcherRef, dispatcher: unknown): void => {
137
- if ("H" in ref) {
138
- ref.H = dispatcher;
139
- } else {
140
- ref.current = dispatcher;
141
- }
142
- };
143
-
144
130
  const pushHookLogEntry = (
145
131
  primitive: string,
146
132
  value: unknown,
@@ -157,7 +143,7 @@ const pushHookLogEntry = (
157
143
  };
158
144
 
159
145
  const dispatcherUse = (usable: unknown): unknown => {
160
- if (isObjectRecord(usable)) {
146
+ if (typeof usable === "object" && usable !== null) {
161
147
  if (isInspectableThenable(usable)) {
162
148
  const cachedThenable =
163
149
  currentThenableState !== null && currentThenableIndex < currentThenableState.length
@@ -176,7 +162,7 @@ const dispatcherUse = (usable: unknown): unknown => {
176
162
  pushHookLogEntry("Unresolved", thenable, "Use");
177
163
  throw SuspenseException;
178
164
  }
179
- if (usable.$$typeof === REACT_CONTEXT_TYPE && "_currentValue" in usable) {
165
+ if ("$$typeof" in usable && usable.$$typeof === REACT_CONTEXT_TYPE && isReactContext(usable)) {
180
166
  const context: InspectableReactContext = {
181
167
  _currentValue: usable._currentValue,
182
168
  displayName: typeof usable.displayName === "string" ? usable.displayName : undefined,
@@ -186,7 +172,7 @@ const dispatcherUse = (usable: unknown): unknown => {
186
172
  return value;
187
173
  }
188
174
  }
189
- throw new BippyHookInspectionError("An unsupported type was passed to use(): " + String(usable));
175
+ throw new BippyHookInspectionError("use() received an unsupported value: " + String(usable));
190
176
  };
191
177
 
192
178
  const dispatcherUseContext = (context: InspectableReactContext): unknown => {
@@ -251,10 +237,7 @@ const dispatcherUseEffect = (create: () => void): void => {
251
237
 
252
238
  const dispatcherUseImperativeHandle = (ref: unknown): void => {
253
239
  nextHook();
254
- let instance: unknown;
255
- if (ref !== null && typeof ref === "object" && "current" in ref) {
256
- instance = ref.current;
257
- }
240
+ const instance = isInspectableRef(ref) ? ref.current : undefined;
258
241
  pushHookLogEntry("ImperativeHandle", instance, "ImperativeHandle");
259
242
  };
260
243
 
@@ -380,15 +363,8 @@ const createActionStateDispatcher =
380
363
  const hook = nextHook();
381
364
  nextHook();
382
365
  nextHook();
383
- const stackError = new Error();
384
366
  const { value, error } = inspectActionStateHook(hook, initialState);
385
- hookLog.push({
386
- displayName: null,
387
- primitive,
388
- stackError,
389
- value,
390
- dispatcherHookName: primitive,
391
- });
367
+ pushHookLogEntry(primitive, value, primitive);
392
368
  if (error !== null) throw error;
393
369
  return [value, () => {}, false];
394
370
  };
@@ -436,15 +412,12 @@ const dispatcher = {
436
412
  useEffectEvent: dispatcherUseEffectEvent,
437
413
  };
438
414
 
439
- const dispatcherProxy =
440
- typeof Proxy === "undefined"
441
- ? dispatcher
442
- : new Proxy(dispatcher, {
443
- get(target, propertyName: string) {
444
- if (Object.hasOwn(target, propertyName)) return Reflect.get(target, propertyName);
445
- throw new BippyUnsupportedHookError("Missing method in Dispatcher: " + propertyName);
446
- },
447
- });
415
+ const dispatcherProxy = new Proxy(dispatcher, {
416
+ get(target, propertyName: string) {
417
+ if (Object.hasOwn(target, propertyName)) return Reflect.get(target, propertyName);
418
+ throw new BippyUnsupportedHookError("The React dispatcher is missing method " + propertyName);
419
+ },
420
+ });
448
421
 
449
422
  const getPrimitiveStackCache = (): Map<string, StackFrame[]> => {
450
423
  if (primitiveStackCache !== null) return primitiveStackCache;
@@ -457,7 +430,7 @@ const getPrimitiveStackCache = (): Map<string, StackFrame[]> => {
457
430
  dispatcher.useState(null);
458
431
  dispatcher.useReducer((state: unknown) => state, null);
459
432
  dispatcher.useRef(null);
460
- if (typeof dispatcher.useCacheRefresh === "function") dispatcher.useCacheRefresh();
433
+ dispatcher.useCacheRefresh();
461
434
  dispatcher.useLayoutEffect(() => {});
462
435
  dispatcher.useInsertionEffect(() => {});
463
436
  dispatcher.useEffect(() => {});
@@ -475,19 +448,16 @@ const getPrimitiveStackCache = (): Map<string, StackFrame[]> => {
475
448
  dispatcher.useFormState((state: unknown) => state, null);
476
449
  dispatcher.useActionState((state: unknown) => state, null);
477
450
  dispatcher.useHostTransitionStatus();
478
- if (typeof dispatcher.useMemoCache === "function") dispatcher.useMemoCache(0);
479
- if (typeof dispatcher.use === "function") {
480
- dispatcher.use({ $$typeof: REACT_CONTEXT_TYPE, _currentValue: null });
481
- const fulfilledPromise = Promise.resolve(null);
482
- Reflect.set(fulfilledPromise, "status", "fulfilled");
483
- Reflect.set(fulfilledPromise, "value", null);
484
- dispatcher.use(fulfilledPromise);
485
- try {
486
- dispatcher.use(new Promise<never>(() => {}));
487
- } catch {}
488
- }
451
+ dispatcher.use({ $$typeof: REACT_CONTEXT_TYPE, _currentValue: null });
452
+ const fulfilledPromise = Promise.resolve(null);
453
+ Reflect.set(fulfilledPromise, "status", "fulfilled");
454
+ Reflect.set(fulfilledPromise, "value", null);
455
+ dispatcher.use(fulfilledPromise);
456
+ try {
457
+ dispatcher.use(new Promise<never>(() => {}));
458
+ } catch {}
489
459
  dispatcher.useId();
490
- if (typeof dispatcher.useEffectEvent === "function") dispatcher.useEffectEvent(() => {});
460
+ dispatcher.useEffectEvent(() => {});
491
461
  } finally {
492
462
  capturedHookLog = hookLog;
493
463
  hookLog = [];
@@ -718,7 +688,10 @@ const setupContexts = (contextMap: Map<ReactContext<unknown>, unknown>, fiber: F
718
688
  while (current) {
719
689
  if (current.tag === getReactWorkTagsForFiber(current).ContextProvider) {
720
690
  const providerType = current.type;
721
- const nestedContext = isObjectRecord(providerType) ? providerType._context : undefined;
691
+ const nestedContext =
692
+ typeof providerType === "object" && providerType !== null && "_context" in providerType
693
+ ? providerType._context
694
+ : undefined;
722
695
  const context = isReactContext(nestedContext)
723
696
  ? nestedContext
724
697
  : isReactContext(providerType)
@@ -742,7 +715,7 @@ const restoreContexts = (contextMap: Map<ReactContext<unknown>, unknown>): void
742
715
  const handleRenderFunctionError = (error: unknown): void => {
743
716
  if (error === SuspenseException) return;
744
717
  if (error instanceof BippyUnsupportedHookError) throw error;
745
- throw new BippyHookRenderError("Error rendering inspected component", error);
718
+ throw new BippyHookRenderError("Bippy couldn’t render the inspected component", error);
746
719
  };
747
720
 
748
721
  const resolveDefaultProps = (
@@ -753,13 +726,14 @@ const resolveDefaultProps = (
753
726
  component &&
754
727
  typeof component === "object" &&
755
728
  "defaultProps" in component &&
756
- isObjectRecord(component.defaultProps)
729
+ typeof component.defaultProps === "object" &&
730
+ component.defaultProps !== null
757
731
  ) {
758
732
  const props = { ...baseProps };
759
733
  const defaultProps = component.defaultProps;
760
- for (const propName in defaultProps) {
734
+ for (const [propName, value] of Object.entries(defaultProps)) {
761
735
  if (props[propName] === undefined) {
762
- props[propName] = defaultProps[propName];
736
+ props[propName] = value;
763
737
  }
764
738
  }
765
739
  return props;
@@ -790,8 +764,8 @@ const performDispatcherInspection = (
790
764
  dispatcherRef: RendererDispatcherRef,
791
765
  renderFn: () => void,
792
766
  ): HooksTree => {
793
- const previousDispatcher = getDispatcherFromRef(dispatcherRef);
794
- setDispatcherOnRef(dispatcherRef, dispatcherProxy);
767
+ const previousDispatcher = readDispatcher(dispatcherRef);
768
+ writeDispatcher(dispatcherRef, dispatcherProxy);
795
769
 
796
770
  let capturedHookLog: HookLogEntry[] = [];
797
771
  let ancestorStackError: Error | undefined;
@@ -804,7 +778,7 @@ const performDispatcherInspection = (
804
778
  } finally {
805
779
  capturedHookLog = hookLog;
806
780
  hookLog = [];
807
- setDispatcherOnRef(dispatcherRef, previousDispatcher);
781
+ writeDispatcher(dispatcherRef, previousDispatcher);
808
782
  }
809
783
 
810
784
  const rootStack = ancestorStackError !== undefined ? parseErrorStack(ancestorStackError) : [];
@@ -812,33 +786,40 @@ const performDispatcherInspection = (
812
786
  };
813
787
 
814
788
  const requireDispatcherRef = (): RendererDispatcherRef => {
815
- const dispatcherRef = getDispatcherRef();
789
+ const dispatcherRef = getRendererDispatcherRefs()[0];
816
790
  if (!dispatcherRef) {
817
791
  throw new BippyHookInspectionError(
818
- "No React renderer found. Make sure React is loaded and bippy's hook is installed.",
792
+ "Bippy couldn’t find a React renderer. Load React and install Bippy’s hook.",
819
793
  );
820
794
  }
821
795
  return dispatcherRef;
822
796
  };
823
797
 
824
798
  const resolveContextDependency = (fiber: Fiber): void => {
799
+ const legacyDependenciesKey = ["dependencies_old", "dependencies_new"].find((key) =>
800
+ Object.hasOwn(fiber, key),
801
+ );
825
802
  if (Object.hasOwn(fiber, "dependencies")) {
826
803
  const dependencies = fiber.dependencies;
827
804
  currentContextDependency = dependencies !== null ? dependencies.firstContext : null;
828
- } else if (Object.hasOwn(fiber, "dependencies_old")) {
829
- const dependencies: unknown = Reflect.get(fiber, "dependencies_old");
830
- const firstContext = isObjectRecord(dependencies) ? dependencies.firstContext : null;
831
- currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
832
- } else if (Object.hasOwn(fiber, "dependencies_new")) {
833
- const dependencies: unknown = Reflect.get(fiber, "dependencies_new");
834
- const firstContext = isObjectRecord(dependencies) ? dependencies.firstContext : null;
805
+ } else if (legacyDependenciesKey) {
806
+ const dependencies: unknown = Reflect.get(fiber, legacyDependenciesKey);
807
+ const firstContext =
808
+ typeof dependencies === "object" && dependencies !== null && "firstContext" in dependencies
809
+ ? dependencies.firstContext
810
+ : null;
835
811
  currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
836
812
  } else if (Object.hasOwn(fiber, "contextDependencies")) {
837
813
  const contextDependencies: unknown = Reflect.get(fiber, "contextDependencies");
838
- const firstContext = isObjectRecord(contextDependencies) ? contextDependencies.first : null;
814
+ const firstContext =
815
+ typeof contextDependencies === "object" &&
816
+ contextDependencies !== null &&
817
+ "first" in contextDependencies
818
+ ? contextDependencies.first
819
+ : null;
839
820
  currentContextDependency = isContextDependency(firstContext) ? firstContext : null;
840
821
  } else {
841
- throw new BippyHookInspectionError("Unsupported React version.");
822
+ throw new BippyHookInspectionError("Bippy doesn’t support this React version.");
842
823
  }
843
824
  };
844
825
 
@@ -851,9 +832,7 @@ export const getFiberHooks = (fiber: Fiber): HooksTree => {
851
832
  fiber.tag !== workTags.SimpleMemoComponent &&
852
833
  fiber.tag !== workTags.ForwardRef
853
834
  ) {
854
- throw new BippyHookInspectionError(
855
- "Unknown Fiber. Needs to be a function component to inspect hooks.",
856
- );
835
+ throw new BippyHookInspectionError("Hook inspection requires a function component Fiber.");
857
836
  }
858
837
 
859
838
  getPrimitiveStackCache();