Type `react-devtools-hook-installer` and `react-devtools-hook-settings-injector` messages (#35586)
Sebastian "Sebbie" Silbermann committed
Jan 21, 2026 at 19:13 UTC
cdbd55f44004cf77a61c178952e34d4514414519
8 files changed
+106
-44
.eslintrc.js
+1
@@ -593,6 +593,7 @@ module.exports = {
593
mixin$Animatable: 'readonly',
594
MouseEventHandler: 'readonly',
595
NavigateEvent: 'readonly',
596
+ Partial: 'readonly',
597
PerformanceMeasureOptions: 'readonly',
598
PropagationPhases: 'readonly',
599
PropertyDescriptor: 'readonly',
flow-typed/environments/bom.js
+8
-8
@@ -826,7 +826,7 @@ declare class WebSocket extends EventTarget {
826
bufferedAmount: number;
827
extensions: string;
828
onopen: (ev: any) => mixed;
829
- onmessage: (ev: MessageEvent) => mixed;
829
+ onmessage: (ev: MessageEvent<>) => mixed;
830
onclose: (ev: CloseEvent) => mixed;
831
onerror: (ev: any) => mixed;
832
binaryType: 'blob' | 'arraybuffer';
@@ -855,8 +855,8 @@ declare class Worker extends EventTarget {
855
workerOptions?: WorkerOptions
856
): void;
857
onerror: null | ((ev: any) => mixed);
858
- onmessage: null | ((ev: MessageEvent) => mixed);
859
- onmessageerror: null | ((ev: MessageEvent) => mixed);
858
+ onmessage: null | ((ev: MessageEvent<>) => mixed);
859
+ onmessageerror: null | ((ev: MessageEvent<>) => mixed);
860
postMessage(message: any, ports?: any): void;
861
terminate(): void;
862
}
@@ -888,14 +888,14 @@ declare class WorkerGlobalScope extends EventTarget {
888
}
889
890
declare class DedicatedWorkerGlobalScope extends WorkerGlobalScope {
891
- onmessage: (ev: MessageEvent) => mixed;
892
- onmessageerror: (ev: MessageEvent) => mixed;
891
+ onmessage: (ev: MessageEvent<>) => mixed;
892
+ onmessageerror: (ev: MessageEvent<>) => mixed;
893
postMessage(message: any, transfer?: Iterable<any>): void;
894
}
895
896
declare class SharedWorkerGlobalScope extends WorkerGlobalScope {
897
name: string;
898
- onconnect: (ev: MessageEvent) => mixed;
898
+ onconnect: (ev: MessageEvent<>) => mixed;
899
}
900
901
declare class WorkerLocation {
@@ -2056,8 +2056,8 @@ declare class MessagePort extends EventTarget {
2056
start(): void;
2057
close(): void;
2058
2059
- onmessage: null | ((ev: MessageEvent) => mixed);
2060
- onmessageerror: null | ((ev: MessageEvent) => mixed);
2059
+ onmessage: null | ((ev: MessageEvent<>) => mixed);
2060
+ onmessageerror: null | ((ev: MessageEvent<>) => mixed);
2061
}
2062
2063
declare class MessageChannel {
flow-typed/environments/dom.js
+3
-3
@@ -151,7 +151,7 @@ type TransitionEventHandler = (event: TransitionEvent) => mixed;
151
type TransitionEventListener =
152
| {handleEvent: TransitionEventHandler, ...}
153
| TransitionEventHandler;
154
-type MessageEventHandler = (event: MessageEvent) => mixed;
154
+type MessageEventHandler = (event: MessageEvent<>) => mixed;
155
type MessageEventListener =
156
| {handleEvent: MessageEventHandler, ...}
157
| MessageEventHandler;
@@ -845,8 +845,8 @@ declare class PageTransitionEvent extends Event {
845
// https://www.w3.org/TR/2008/WD-html5-20080610/comms.html
846
// and
847
// https://html.spec.whatwg.org/multipage/comms.html#the-messageevent-interfaces
848
-declare class MessageEvent extends Event {
849
- data: mixed;
848
+declare class MessageEvent<Data = mixed> extends Event {
849
+ data: Data;
850
origin: string;
851
lastEventId: string;
852
source: WindowProxy;
flow-typed/environments/html.js
+2
-2
@@ -109,8 +109,8 @@ declare class ErrorEvent extends Event {
109
// https://html.spec.whatwg.org/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts
110
declare class BroadcastChannel extends EventTarget {
111
name: string;
112
- onmessage: ?(event: MessageEvent) => void;
113
- onmessageerror: ?(event: MessageEvent) => void;
112
+ onmessage: ?(event: MessageEvent<>) => void;
113
+ onmessageerror: ?(event: MessageEvent<>) => void;
114
115
constructor(name: string): void;
116
postMessage(msg: mixed): void;
packages/react-devtools-core/src/backend.js
+1
-1
@@ -293,7 +293,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
293
scheduleRetry();
294
}
295
296
- function handleMessage(event: MessageEvent) {
296
+ function handleMessage(event: MessageEvent<>) {
297
let data;
298
try {
299
if (typeof event.data === 'string') {
packages/react-devtools-extensions/src/contentScripts/hookSettingsInjector.js
+34
-22
@@ -1,38 +1,50 @@
1
/* global chrome */
2
+/** @flow */
3
4
// We can't use chrome.storage domain from scripts which are injected in ExecutionWorld.MAIN
5
// This is the only purpose of this script - to send persisted settings to installHook.js content script
6
6
-async function messageListener(event: MessageEvent) {
7
+import type {UnknownMessageEvent} from './messages';
8
+import type {DevToolsHookSettings} from 'react-devtools-shared/src/backend/types';
9
+import {postMessage} from './messages';
10
+
11
+async function messageListener(event: UnknownMessageEvent) {
12
if (event.source !== window) {
13
return;
14
}
15
16
if (event.data.source === 'react-devtools-hook-installer') {
17
if (event.data.payload.handshake) {
13
- const settings = await chrome.storage.local.get();
18
+ const settings: Partial<DevToolsHookSettings> =
19
+ await chrome.storage.local.get();
20
// If storage was empty (first installation), define default settings
15
- if (typeof settings.appendComponentStack !== 'boolean') {
16
- settings.appendComponentStack = true;
17
- }
18
- if (typeof settings.breakOnConsoleErrors !== 'boolean') {
19
- settings.breakOnConsoleErrors = false;
20
- }
21
- if (typeof settings.showInlineWarningsAndErrors !== 'boolean') {
22
- settings.showInlineWarningsAndErrors = true;
23
- }
24
- if (typeof settings.hideConsoleLogsInStrictMode !== 'boolean') {
25
- settings.hideConsoleLogsInStrictMode = false;
26
- }
27
- if (
28
- typeof settings.disableSecondConsoleLogDimmingInStrictMode !== 'boolean'
29
- ) {
30
- settings.disableSecondConsoleLogDimmingInStrictMode = false;
31
- }
21
+ const hookSettings: DevToolsHookSettings = {
22
+ appendComponentStack:
23
+ typeof settings.appendComponentStack === 'boolean'
24
+ ? settings.appendComponentStack
25
+ : true,
26
+ breakOnConsoleErrors:
27
+ typeof settings.breakOnConsoleErrors === 'boolean'
28
+ ? settings.breakOnConsoleErrors
29
+ : false,
30
+ showInlineWarningsAndErrors:
31
+ typeof settings.showInlineWarningsAndErrors === 'boolean'
32
+ ? settings.showInlineWarningsAndErrors
33
+ : true,
34
+ hideConsoleLogsInStrictMode:
35
+ typeof settings.hideConsoleLogsInStrictMode === 'boolean'
36
+ ? settings.hideConsoleLogsInStrictMode
37
+ : false,
38
+ disableSecondConsoleLogDimmingInStrictMode:
39
+ typeof settings.disableSecondConsoleLogDimmingInStrictMode ===
40
+ 'boolean'
41
+ ? settings.disableSecondConsoleLogDimmingInStrictMode
42
+ : false,
43
+ };
44
33
- window.postMessage({
45
+ postMessage({
46
source: 'react-devtools-hook-settings-injector',
35
- payload: {settings},
47
+ payload: {settings: hookSettings},
48
});
49
50
window.removeEventListener('message', messageListener);
@@ -41,7 +53,7 @@ async function messageListener(event: MessageEvent) {
53
}
54
55
window.addEventListener('message', messageListener);
44
-window.postMessage({
56
+postMessage({
57
source: 'react-devtools-hook-settings-injector',
58
payload: {handshake: true},
59
});
packages/react-devtools-extensions/src/contentScripts/installHook.js
+15
-8
@@ -1,39 +1,46 @@
1
+/** @flow */
2
+
3
+import type {UnknownMessageEvent} from './messages';
4
+import type {DevToolsHookSettings} from 'react-devtools-shared/src/backend/types';
5
+
6
import {installHook} from 'react-devtools-shared/src/hook';
7
import {
8
getIfReloadedAndProfiling,
9
getProfilingSettings,
10
} from 'react-devtools-shared/src/utils';
11
+import {postMessage} from './messages';
12
7
-let resolveHookSettingsInjection;
13
+let resolveHookSettingsInjection: (settings: DevToolsHookSettings) => void;
14
9
-function messageListener(event: MessageEvent) {
15
+function messageListener(event: UnknownMessageEvent) {
16
if (event.source !== window) {
17
return;
18
}
19
20
if (event.data.source === 'react-devtools-hook-settings-injector') {
21
+ const payload = event.data.payload;
22
// In case handshake message was sent prior to hookSettingsInjector execution
23
// We can't guarantee order
17
- if (event.data.payload.handshake) {
18
- window.postMessage({
24
+ if (payload.handshake) {
25
+ postMessage({
26
source: 'react-devtools-hook-installer',
27
payload: {handshake: true},
28
});
22
- } else if (event.data.payload.settings) {
29
+ } else if (payload.settings) {
30
window.removeEventListener('message', messageListener);
24
- resolveHookSettingsInjection(event.data.payload.settings);
31
+ resolveHookSettingsInjection(payload.settings);
32
}
33
}
34
}
35
36
// Avoid double execution
37
if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) {
31
- const hookSettingsPromise = new Promise(resolve => {
38
+ const hookSettingsPromise = new Promise<DevToolsHookSettings>(resolve => {
39
resolveHookSettingsInjection = resolve;
40
});
41
42
window.addEventListener('message', messageListener);
36
- window.postMessage({
43
+ postMessage({
44
source: 'react-devtools-hook-installer',
45
payload: {handshake: true},
46
});
packages/react-devtools-extensions/src/contentScripts/messages.js
new
+42
@@ -0,0 +1,42 @@
1
+/** @flow */
2
+
3
+import type {DevToolsHookSettings} from 'react-devtools-shared/src/backend/types';
4
+
5
+export function postMessage(event: UnknownMessageEventData): void {
6
+ window.postMessage(event);
7
+}
8
+
9
+export interface UnknownMessageEvent
10
+ extends MessageEvent<UnknownMessageEventData> {}
11
+
12
+export type UnknownMessageEventData =
13
+ | HookSettingsInjectorEventData
14
+ | HookInstallerEventData;
15
+
16
+export type HookInstallerEventData = {
17
+ source: 'react-devtools-hook-installer',
18
+ payload: HookInstallerEventPayload,
19
+};
20
+
21
+export type HookInstallerEventPayload = HookInstallerEventPayloadHandshake;
22
+
23
+export type HookInstallerEventPayloadHandshake = {
24
+ handshake: true,
25
+};
26
+
27
+export type HookSettingsInjectorEventData = {
28
+ source: 'react-devtools-hook-settings-injector',
29
+ payload: HookSettingsInjectorEventPayload,
30
+};
31
+
32
+export type HookSettingsInjectorEventPayload =
33
+ | HookSettingsInjectorEventPayloadHandshake
34
+ | HookSettingsInjectorEventPayloadSettings;
35
+
36
+export type HookSettingsInjectorEventPayloadHandshake = {
37
+ handshake: true,
38
+};
39
+
40
+export type HookSettingsInjectorEventPayloadSettings = {
41
+ settings: DevToolsHookSettings,
42
+};