bippy 0.7.2 → 0.7.3-dev.0c7e504

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/src/rdt-hook.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // This module must load before React so renderers can inject into the hook.
2
2
 
3
- import type { ReactDevToolsGlobalHook, ReactRenderer } from "./react-internals/index.js";
3
+ import type { FiberRoot, ReactDevToolsGlobalHook, ReactRenderer } from "./react-internals/index.js";
4
4
 
5
5
  export interface Unsubscribe extends Disposable {
6
6
  (): void;
@@ -14,8 +14,17 @@ interface RendererInjectListener {
14
14
  (renderer: ReactRenderer): void;
15
15
  }
16
16
 
17
+ interface RendererInjectSubscription {
18
+ listener: RendererInjectListener;
19
+ target: ReactDevToolsTarget;
20
+ }
21
+
17
22
  interface RDTHookReplaceListener {
18
- (rdtHook: ReactDevToolsGlobalHook): void;
23
+ (rdtHook: ReactDevToolsGlobalHook, target: ReactDevToolsTarget): void;
24
+ }
25
+
26
+ export interface ReactDevToolsTarget {
27
+ __REACT_DEVTOOLS_GLOBAL_HOOK__?: ReactDevToolsGlobalHook;
19
28
  }
20
29
 
21
30
  export const version = process.env.VERSION;
@@ -25,10 +34,23 @@ const objectDefineProperty = Object.defineProperty;
25
34
 
26
35
  const noOp = (): void => {};
27
36
 
37
+ const getTargetHook = (target: ReactDevToolsTarget): ReactDevToolsGlobalHook | undefined =>
38
+ target.__REACT_DEVTOOLS_GLOBAL_HOOK__;
39
+
28
40
  export const createUnsubscribe = (unsubscribe: () => void): Unsubscribe =>
29
41
  Object.assign(unsubscribe, { [Symbol.dispose]: unsubscribe });
30
42
 
43
+ export const isFiberRootUnmounted = (fiberRoot: FiberRoot): boolean => {
44
+ const rootState = fiberRoot.current.memoizedState;
45
+ return (
46
+ rootState === null ||
47
+ (rootState !== undefined && (rootState.element === null || rootState.element === undefined))
48
+ );
49
+ };
50
+
31
51
  const checkDCE = (functionToCheck: unknown): void => {
52
+ // HACK: Node loads React's unbundled entrypoints, where development guards are intentionally not eliminated.
53
+ if (typeof process !== "undefined" && process.versions?.node) return;
32
54
  try {
33
55
  const code = Function.prototype.toString.call(functionToCheck);
34
56
  if (code.indexOf("^_^") > -1) {
@@ -47,7 +69,7 @@ const checkDCE = (functionToCheck: unknown): void => {
47
69
  export const isRealReactDevtools = (
48
70
  rdtHook: ReactDevToolsGlobalHook | undefined | null = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__,
49
71
  ): boolean => {
50
- return Boolean(rdtHook && "getFiberRoots" in rdtHook);
72
+ return Boolean(rdtHook && "getFiberRoots" in rdtHook && rdtHook._isBippyHook !== true);
51
73
  };
52
74
 
53
75
  // HACK: react-refresh's inject wrapper is the only stock hook whose parameter is named
@@ -69,53 +91,63 @@ export const _onActiveListeners = new Set<ActiveListener>();
69
91
 
70
92
  export const _renderers = new Set<ReactRenderer>();
71
93
 
72
- const rendererInjectListeners = new Set<RendererInjectListener>();
94
+ const activeListenerTargets = new WeakMap<ActiveListener, Set<ReactDevToolsTarget>>();
95
+ const rendererInjectSubscriptions = new Set<RendererInjectSubscription>();
73
96
  const rdtHookReplaceListeners = new Set<RDTHookReplaceListener>();
74
- // HACK: Hook replacement can leave an old inject wrapper in the call chain, so notifications must be deduplicated.
75
- const notifiedRenderers = new WeakSet<ReactRenderer>();
76
- const notifyingInjectByHook = new WeakMap<
77
- ReactDevToolsGlobalHook,
78
- ReactDevToolsGlobalHook["inject"]
79
- >();
80
-
81
- const notifyActiveListeners = (): void => {
82
- for (const listener of _onActiveListeners) {
83
- listener();
97
+ const notifiedRenderersByTarget = new WeakMap<ReactDevToolsTarget, WeakSet<ReactRenderer>>();
98
+
99
+ const addActiveListener = (listener: ActiveListener, target: ReactDevToolsTarget): void => {
100
+ _onActiveListeners.add(listener);
101
+ const targets = activeListenerTargets.get(listener) ?? new Set<ReactDevToolsTarget>();
102
+ targets.add(target);
103
+ activeListenerTargets.set(listener, targets);
104
+ };
105
+
106
+ export const removeActiveListener = (
107
+ listener: ActiveListener,
108
+ target: ReactDevToolsTarget,
109
+ ): void => {
110
+ const targets = activeListenerTargets.get(listener);
111
+ targets?.delete(target);
112
+ if (!targets || targets.size === 0) {
113
+ activeListenerTargets.delete(listener);
114
+ _onActiveListeners.delete(listener);
84
115
  }
85
116
  };
86
117
 
87
- const notifyRendererInjectListeners = (renderer: ReactRenderer): void => {
88
- for (const listener of rendererInjectListeners) {
89
- listener(renderer);
118
+ const notifyActiveListeners = (target: ReactDevToolsTarget): void => {
119
+ for (const listener of _onActiveListeners) {
120
+ if (activeListenerTargets.get(listener)?.has(target)) listener();
90
121
  }
91
122
  };
92
123
 
93
- const notifyRDTHookReplaceListeners = (rdtHook: ReactDevToolsGlobalHook): void => {
94
- for (const listener of rdtHookReplaceListeners) {
95
- listener(rdtHook);
124
+ const notifyRendererInjectListeners = (
125
+ target: ReactDevToolsTarget,
126
+ renderer: ReactRenderer,
127
+ ): void => {
128
+ for (const subscription of rendererInjectSubscriptions) {
129
+ if (subscription.target === target) subscription.listener(renderer);
96
130
  }
97
131
  };
98
132
 
99
- const setRendererInjectDispatcher = (rdtHook: ReactDevToolsGlobalHook): void => {
100
- if (rdtHook.inject === notifyingInjectByHook.get(rdtHook)) return;
101
- const previousInject = rdtHook.inject;
102
- const nextInject = (renderer: ReactRenderer) => {
103
- const rendererId = previousInject.call(rdtHook, renderer);
104
- if (!notifiedRenderers.has(renderer)) {
105
- notifiedRenderers.add(renderer);
106
- notifyRendererInjectListeners(renderer);
107
- }
108
- return rendererId;
109
- };
110
- rdtHook.inject = nextInject;
111
- notifyingInjectByHook.set(rdtHook, nextInject);
133
+ const notifyRDTHookReplaceListeners = (
134
+ rdtHook: ReactDevToolsGlobalHook,
135
+ target: ReactDevToolsTarget,
136
+ ): void => {
137
+ for (const listener of rdtHookReplaceListeners) {
138
+ listener(rdtHook, target);
139
+ }
112
140
  };
113
141
 
114
- export const onRendererInject = (listener: RendererInjectListener): Unsubscribe => {
115
- setRendererInjectDispatcher(getRDTHook());
116
- rendererInjectListeners.add(listener);
142
+ export const onRendererInject = (
143
+ listener: RendererInjectListener,
144
+ target: ReactDevToolsTarget = globalThis,
145
+ ): Unsubscribe => {
146
+ getRDTHook(undefined, target);
147
+ const subscription = { listener, target };
148
+ rendererInjectSubscriptions.add(subscription);
117
149
  return createUnsubscribe(() => {
118
- rendererInjectListeners.delete(listener);
150
+ rendererInjectSubscriptions.delete(subscription);
119
151
  });
120
152
  };
121
153
 
@@ -126,8 +158,13 @@ export const onRDTHookReplace = (listener: RDTHookReplaceListener): Unsubscribe
126
158
  });
127
159
  };
128
160
 
161
+ // A Map built in another realm (an iframe target) fails instanceof, so replacing it
162
+ // would discard that realm's renderer registry. Object.prototype.toString is realm-agnostic.
163
+ export const isRendererMap = (value: unknown): value is Map<number, ReactRenderer> =>
164
+ Object.prototype.toString.call(value) === "[object Map]";
165
+
129
166
  const getRendererMap = (rdtHook: ReactDevToolsGlobalHook): Map<number, ReactRenderer> => {
130
- if (!(rdtHook.renderers instanceof Map)) {
167
+ if (!isRendererMap(rdtHook.renderers)) {
131
168
  rdtHook.renderers = new Map();
132
169
  }
133
170
  return rdtHook.renderers;
@@ -135,6 +172,7 @@ const getRendererMap = (rdtHook: ReactDevToolsGlobalHook): Map<number, ReactRend
135
172
 
136
173
  const trackInjectedRenderer = (
137
174
  rdtHook: ReactDevToolsGlobalHook,
175
+ target: ReactDevToolsTarget,
138
176
  renderers: Map<number, ReactRenderer>,
139
177
  rendererId: number,
140
178
  renderer: ReactRenderer,
@@ -143,28 +181,47 @@ const trackInjectedRenderer = (
143
181
  _renderers.add(renderer);
144
182
  if (!rdtHook._instrumentationIsActive) {
145
183
  rdtHook._instrumentationIsActive = true;
146
- notifyActiveListeners();
184
+ notifyActiveListeners(target);
147
185
  }
186
+ const notifiedRenderers = notifiedRenderersByTarget.get(target) ?? new WeakSet<ReactRenderer>();
187
+ notifiedRenderersByTarget.set(target, notifiedRenderers);
188
+ if (notifiedRenderers.has(renderer)) return;
189
+ notifiedRenderers.add(renderer);
190
+ notifyRendererInjectListeners(target, renderer);
148
191
  };
149
192
 
150
- export const installRDTHook = (onActive?: ActiveListener): ReactDevToolsGlobalHook => {
151
- if (onActive) {
152
- _onActiveListeners.add(onActive);
153
- }
193
+ export const installRDTHook = (
194
+ onActive?: ActiveListener,
195
+ target: ReactDevToolsTarget = globalThis,
196
+ ): ReactDevToolsGlobalHook => {
197
+ if (onActive) addActiveListener(onActive, target);
154
198
  const renderers = new Map<number, ReactRenderer>();
199
+ const fiberRoots = new Map<number, Set<FiberRoot>>();
200
+ // Callers register roots by mutating the returned set, so it must be memoized.
201
+ const getRendererFiberRoots = (rendererId: number): Set<FiberRoot> => {
202
+ const rendererRoots = fiberRoots.get(rendererId) ?? new Set<FiberRoot>();
203
+ fiberRoots.set(rendererId, rendererRoots);
204
+ return rendererRoots;
205
+ };
155
206
  let rendererIdCounter = 0;
156
207
  let rdtHook: ReactDevToolsGlobalHook = {
157
208
  _instrumentationIsActive: false,
158
209
  _instrumentationSource: BIPPY_INSTRUMENTATION_STRING,
210
+ _isBippyHook: true,
159
211
  checkDCE,
212
+ getFiberRoots: getRendererFiberRoots,
160
213
  hasUnsupportedRendererAttached: false,
161
214
  inject: (renderer) => {
162
215
  const nextRendererId = ++rendererIdCounter;
163
- trackInjectedRenderer(rdtHook, renderers, nextRendererId, renderer);
216
+ trackInjectedRenderer(rdtHook, target, renderers, nextRendererId, renderer);
164
217
  return nextRendererId;
165
218
  },
166
219
  on: noOp,
167
- onCommitFiberRoot: noOp,
220
+ onCommitFiberRoot: (rendererId, fiberRoot) => {
221
+ const rendererRoots = getRendererFiberRoots(rendererId);
222
+ if (isFiberRootUnmounted(fiberRoot)) rendererRoots.delete(fiberRoot);
223
+ else rendererRoots.add(fiberRoot);
224
+ },
168
225
  onCommitFiberUnmount: noOp,
169
226
  onPostCommitFiberRoot: noOp,
170
227
  renderers,
@@ -172,13 +229,11 @@ export const installRDTHook = (onActive?: ActiveListener): ReactDevToolsGlobalHo
172
229
  supportsFlight: true,
173
230
  };
174
231
  try {
175
- objectDefineProperty(globalThis, "__REACT_DEVTOOLS_GLOBAL_HOOK__", {
232
+ objectDefineProperty(target, "__REACT_DEVTOOLS_GLOBAL_HOOK__", {
176
233
  configurable: true,
177
234
  enumerable: true,
178
- get() {
179
- return rdtHook;
180
- },
181
- set(newHook) {
235
+ get: () => rdtHook,
236
+ set: (newHook: ReactDevToolsGlobalHook | undefined) => {
182
237
  if (newHook && typeof newHook === "object") {
183
238
  const ourRenderers = rdtHook.renderers;
184
239
  rdtHook = newHook;
@@ -188,13 +243,13 @@ export const installRDTHook = (onActive?: ActiveListener): ReactDevToolsGlobalHo
188
243
  nextRenderers.set(rendererId, renderer);
189
244
  });
190
245
  if (ourRenderers.size > 0 || rdtHookReplaceListeners.size > 0) {
191
- patchRDTHook(onActive);
246
+ patchRDTHook(onActive, target);
192
247
  }
193
- notifyRDTHookReplaceListeners(rdtHook);
248
+ notifyRDTHookReplaceListeners(rdtHook, target);
194
249
  }
195
250
  },
196
251
  });
197
- if (typeof window !== "undefined") {
252
+ if (target === globalThis && typeof window !== "undefined") {
198
253
  // HACK: The DevTools extension uses hasOwnProperty to decide whether it may replace an earlier hook.
199
254
  const originalWindowHasOwnProperty = window.hasOwnProperty.bind(window);
200
255
  const originalHasOwnPropertyDescriptor = Object.getOwnPropertyDescriptor(
@@ -224,17 +279,18 @@ export const installRDTHook = (onActive?: ActiveListener): ReactDevToolsGlobalHo
224
279
  });
225
280
  }
226
281
  } catch {
227
- patchRDTHook(onActive);
282
+ patchRDTHook(onActive, target);
228
283
  }
229
284
  return rdtHook;
230
285
  };
231
286
 
232
- export const patchRDTHook = (onActive?: ActiveListener): void => {
233
- if (onActive) {
234
- _onActiveListeners.add(onActive);
235
- }
287
+ export const patchRDTHook = (
288
+ onActive?: ActiveListener,
289
+ target: ReactDevToolsTarget = globalThis,
290
+ ): void => {
291
+ if (onActive) addActiveListener(onActive, target);
236
292
  let didNotifyActiveListeners = false;
237
- const rdtHook = globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__;
293
+ const rdtHook = getTargetHook(target);
238
294
  if (!rdtHook) return;
239
295
  const renderers = getRendererMap(rdtHook);
240
296
  if (!rdtHook._instrumentationSource) {
@@ -252,20 +308,20 @@ export const patchRDTHook = (onActive?: ActiveListener): void => {
252
308
  if (renderers.size) {
253
309
  renderers.forEach((renderer) => _renderers.add(renderer));
254
310
  rdtHook._instrumentationIsActive = true;
255
- notifyActiveListeners();
311
+ notifyActiveListeners(target);
256
312
  didNotifyActiveListeners = true;
257
313
  } else if (!isReactDevtools && isReactRefresh(rdtHook)) {
258
314
  // HACK: react-refresh's stub inject never records renderers, so a React app
259
315
  // that injected before bippy loaded is undetectable through the renderers map.
260
316
  // A react-refresh hook implies a dev renderer, so activate immediately.
261
317
  rdtHook._instrumentationIsActive = true;
262
- notifyActiveListeners();
318
+ notifyActiveListeners(target);
263
319
  didNotifyActiveListeners = true;
264
320
  }
265
321
  const previousInject = rdtHook.inject;
266
322
  rdtHook.inject = (renderer) => {
267
323
  const rendererId = previousInject.call(rdtHook, renderer);
268
- trackInjectedRenderer(rdtHook, renderers, rendererId, renderer);
324
+ trackInjectedRenderer(rdtHook, target, renderers, rendererId, renderer);
269
325
  return rendererId;
270
326
  };
271
327
  }
@@ -274,18 +330,20 @@ export const patchRDTHook = (onActive?: ActiveListener): void => {
274
330
  }
275
331
  };
276
332
 
277
- export const hasRDTHook = (): boolean => {
278
- return Object.hasOwn(globalThis, "__REACT_DEVTOOLS_GLOBAL_HOOK__");
279
- };
333
+ export const hasRDTHook = (target: ReactDevToolsTarget = globalThis): boolean =>
334
+ Object.hasOwn(target, "__REACT_DEVTOOLS_GLOBAL_HOOK__");
280
335
 
281
336
  /**
282
337
  * Returns the current React DevTools global hook.
283
338
  */
284
- export const getRDTHook = (onActive?: ActiveListener): ReactDevToolsGlobalHook => {
285
- if (!hasRDTHook()) {
286
- return installRDTHook(onActive);
339
+ export const getRDTHook = (
340
+ onActive?: ActiveListener,
341
+ target: ReactDevToolsTarget = globalThis,
342
+ ): ReactDevToolsGlobalHook => {
343
+ if (!hasRDTHook(target)) {
344
+ return installRDTHook(onActive, target);
287
345
  }
288
346
 
289
- patchRDTHook(onActive);
290
- return globalThis.__REACT_DEVTOOLS_GLOBAL_HOOK__ ?? installRDTHook(onActive);
347
+ patchRDTHook(onActive, target);
348
+ return getTargetHook(target) ?? installRDTHook(onActive, target);
291
349
  };
@@ -0,0 +1,84 @@
1
+ // Adapted from ReactFiberTreeReflection.js. Copyright (c) Meta Platforms, Inc. and affiliates. MIT licensed.
2
+ import type { Fiber } from "./types.js";
3
+ import { getReactWorkTagsForFiber } from "./index.js";
4
+
5
+ export const getCurrentFiberFromRoot = (fiber: Fiber): Fiber | null => {
6
+ const alternate = fiber.alternate;
7
+ if (!alternate) return null;
8
+ let firstBranch = fiber;
9
+ let secondBranch = alternate;
10
+
11
+ while (firstBranch.return) {
12
+ const firstParent = firstBranch.return;
13
+ const secondParent = firstParent.alternate;
14
+ if (!secondParent) {
15
+ const nextParent = firstParent.return;
16
+ if (!nextParent) return null;
17
+ firstBranch = secondBranch = nextParent;
18
+ continue;
19
+ }
20
+
21
+ if (firstParent.child === secondParent.child) {
22
+ let child = firstParent.child;
23
+ while (child) {
24
+ if (child === firstBranch || child === secondBranch) {
25
+ let root = firstParent;
26
+ while (root.return) root = root.return;
27
+ if (root.tag !== getReactWorkTagsForFiber(root).HostRoot) return null;
28
+ return child === firstBranch ? fiber : alternate;
29
+ }
30
+ child = child.sibling;
31
+ }
32
+ return null;
33
+ }
34
+
35
+ if (firstBranch.return !== secondBranch.return) {
36
+ firstBranch = firstParent;
37
+ secondBranch = secondParent;
38
+ } else {
39
+ let didFindChild = false;
40
+ let child = firstParent.child;
41
+ while (child) {
42
+ if (child === firstBranch) {
43
+ firstBranch = firstParent;
44
+ secondBranch = secondParent;
45
+ didFindChild = true;
46
+ break;
47
+ }
48
+ if (child === secondBranch) {
49
+ firstBranch = secondParent;
50
+ secondBranch = firstParent;
51
+ didFindChild = true;
52
+ break;
53
+ }
54
+ child = child.sibling;
55
+ }
56
+ if (!didFindChild) {
57
+ child = secondParent.child;
58
+ while (child) {
59
+ if (child === firstBranch) {
60
+ firstBranch = secondParent;
61
+ secondBranch = firstParent;
62
+ didFindChild = true;
63
+ break;
64
+ }
65
+ if (child === secondBranch) {
66
+ firstBranch = firstParent;
67
+ secondBranch = secondParent;
68
+ didFindChild = true;
69
+ break;
70
+ }
71
+ child = child.sibling;
72
+ }
73
+ if (!didFindChild) return null;
74
+ }
75
+ }
76
+ if (firstBranch.alternate !== secondBranch) return null;
77
+ }
78
+
79
+ if (firstBranch.tag !== getReactWorkTagsForFiber(firstBranch).HostRoot) return null;
80
+ const root = firstBranch.stateNode;
81
+ if (typeof root !== "object" || root === null || !("current" in root)) return null;
82
+ if (root.current === firstBranch) return fiber;
83
+ return root.current === secondBranch ? alternate : null;
84
+ };
@@ -49,11 +49,16 @@ export const getReactWorkTagsForFiber = (fiber: Fiber): Readonly<ReactWorkTagMap
49
49
 
50
50
  const traversedFibers: Fiber[] = [fiber];
51
51
  let rootFiber = fiber;
52
+ let workTags = defaultReactWorkTags;
52
53
  while (rootFiber.return) {
53
54
  rootFiber = rootFiber.return;
55
+ const ancestorWorkTags = fiberReactWorkTags.get(rootFiber);
56
+ if (ancestorWorkTags) {
57
+ workTags = ancestorWorkTags;
58
+ break;
59
+ }
54
60
  traversedFibers.push(rootFiber);
55
61
  }
56
- const workTags = fiberReactWorkTags.get(rootFiber) ?? defaultReactWorkTags;
57
62
  for (const traversedFiber of traversedFibers) {
58
63
  fiberReactWorkTags.set(traversedFiber, workTags);
59
64
  if (traversedFiber.alternate) {
@@ -31,12 +31,30 @@ export interface ServerComponentInfo {
31
31
  env?: string;
32
32
  owner?: Fiber | ServerComponentInfo | null;
33
33
  debugStack?: Error | null;
34
+ debugLocation?: Error | null;
35
+ }
36
+
37
+ export interface ReactIOInfo {
38
+ name: string;
39
+ start: number;
40
+ end: number;
41
+ byteSize?: number;
42
+ value?: Promise<unknown> | null;
43
+ env?: string;
44
+ owner?: ServerComponentInfo | null;
45
+ stack?: unknown[] | null;
46
+ debugStack?: Error | null;
34
47
  }
35
48
 
36
49
  export interface ReactDebugInfo {
37
- debugLocation?: unknown;
50
+ awaited?: ReactIOInfo;
51
+ debugLocation?: Error | null;
38
52
  env?: string;
39
53
  name?: string;
54
+ owner?: ServerComponentInfo | null;
55
+ stack?: unknown[] | null;
56
+ debugStack?: Error | null;
57
+ time?: number;
40
58
  }
41
59
 
42
60
  export interface ReactMemoCache {
@@ -71,10 +89,10 @@ export interface Fiber<T = unknown> extends Omit<
71
89
  | "tag"
72
90
  | "updateQueue"
73
91
  > {
74
- _debugInfo?: ReactDebugInfo[];
92
+ _debugInfo?: ReactDebugInfo[] | null;
75
93
  _debugOwner?: Fiber | ServerComponentInfo | null;
76
94
  _debugSource?: FiberDebugSource | null;
77
- _debugStack?: Error & { stack: string };
95
+ _debugStack?: Error | null;
78
96
  alternate: Fiber | null;
79
97
  child: Fiber | null;
80
98
  deletions: Fiber[] | null;
@@ -96,6 +114,8 @@ export interface HostFiber<T = unknown> extends Fiber<T> {
96
114
 
97
115
  export interface FiberRoot {
98
116
  current: Fiber;
117
+ effectDuration?: number;
118
+ passiveEffectDuration?: number;
99
119
  }
100
120
 
101
121
  export interface MemoizedState {
@@ -115,6 +135,7 @@ export interface ReactDevToolsEventHandler {
115
135
  export interface ReactDevToolsGlobalHook {
116
136
  _instrumentationIsActive?: boolean;
117
137
  _instrumentationSource?: string;
138
+ _isBippyHook?: boolean;
118
139
  checkDCE: (fn: unknown) => void;
119
140
  emit?: (event: string, data?: unknown) => void;
120
141
  getFiberRoots?: (rendererID: number) => Set<FiberRoot>;
@@ -149,14 +170,20 @@ export type RendererDispatcherRef = CurrentDispatcherRef | LegacyDispatcherRef;
149
170
 
150
171
  export interface ReactRenderer extends Omit<
151
172
  ReactReconciler.DevToolsConfig<unknown, unknown, unknown>,
152
- "findFiberByHostInstance"
173
+ "bundleType" | "findFiberByHostInstance"
153
174
  > {
175
+ bundleType: number;
154
176
  currentDispatcherRef?: RendererDispatcherRef | null;
155
177
  findFiberByHostInstance?: (hostInstance: unknown) => Fiber | null;
156
178
  getCurrentFiber?: () => Fiber | null;
157
179
  overrideContext?: (fiber: Fiber, contextType: unknown, path: string[], value: unknown) => void;
158
180
 
159
- overrideHookState?: (fiber: Fiber, id: number, path: string[], value: unknown) => void;
181
+ overrideHookState?: (
182
+ fiber: Fiber,
183
+ id: number,
184
+ path: Array<number | string>,
185
+ value: unknown,
186
+ ) => void;
160
187
  overrideHookStateDeletePath?: (fiber: Fiber, id: number, path: Array<number | string>) => void;
161
188
  overrideHookStateRenamePath?: (
162
189
  fiber: Fiber,
@@ -164,7 +191,7 @@ export interface ReactRenderer extends Omit<
164
191
  oldPath: Array<number | string>,
165
192
  newPath: Array<number | string>,
166
193
  ) => void;
167
- overrideProps?: (fiber: Fiber, path: string[], value: unknown) => void;
194
+ overrideProps?: (fiber: Fiber, path: Array<number | string>, value: unknown) => void;
168
195
  overridePropsDeletePath?: (fiber: Fiber, path: Array<number | string>) => void;
169
196
  overridePropsRenamePath?: (
170
197
  fiber: Fiber,