mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
feature(dev-middleware): add custom message handlers to extend CDP capabilities (#43291)
Summary:
This is a proposal for the `react-native/dev-middleware` package, to allow implementers to extend the CDP capabilities of the `InspectorProxy`. It's unfortunately needed until we can move to the native Hermes CDP layer.
At Expo, we extend the CDP capabilities of this `InspectorProxy` by injecting functionality on the device level. This proposed API does the same, but without having to overwrite internal functions of both the `InspectorProxy` and `InspectorDevice`.
A good example of this is the network inspector's capabilities. This currently works through the inspection proxy, and roughly like:
- Handle any incoming `Expo(Network.receivedResponseBody)` from the _**device**_, store it, and stop event from propagating
- Handle the incoming `Network.getResponseBody` from the _**debugger**_, return the data, and stop event from propagating.
This API brings back that capability in a more structured way.
## API:
```ts
import { createDevMiddleware } from 'react-native/dev-middleware';
const { middleware, websocketEndpoints } = createDevMiddleware({
unstable_customInspectorMessageHandler: ({ page, deviceInfo, debuggerInfo }) => {
// Do not enable handler for page other than "SOMETHING", or for vscode debugging
// Can also include `page.capabilities` to determine if handler is required
if (page.title !== 'SOMETHING' || debuggerInfo.userAgent?.includes('vscode')) {
return null;
}
return {
handleDeviceMessage(message) {
if (message.type === 'CDP_MESSAGE') {
// Do something and stop message from propagating with return `true`
return true;
}
},
handleDebuggerMessage(message) {
if (message.type === 'CDP_MESSAGE') {
// Do something and stop message from propagating with return `true`
return true;
}
},
};
},
});
```
## Changelog:
<!-- Help reviewers and the release process by writing your own changelog entry.
Pick one each for the category and type tags:
For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->
[GENERAL] [ADDED] - Add inspector proxy device message middleware API
Pull Request resolved: https://github.com/facebook/react-native/pull/43291
Test Plan: See added tests and code above
Reviewed By: huntie
Differential Revision: D54804503
Pulled By: motiz88
fbshipit-source-id: ae918dcd5b7e76d3fb31db4c84717567ae60fa96
This commit is contained in:
committed by
Facebook GitHub Bot
parent
5833eb59e3
commit
3f41fb5d5b
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import {createAndConnectTarget} from './InspectorProtocolUtils';
|
||||
import {withAbortSignalForEachTest} from './ResourceUtils';
|
||||
import {baseUrlForServer, createServer} from './ServerUtils';
|
||||
import until from 'wait-for-expect';
|
||||
|
||||
// WebSocket is unreliable when using fake timers.
|
||||
jest.useRealTimers();
|
||||
|
||||
jest.setTimeout(10000);
|
||||
|
||||
describe('inspector proxy device message middleware', () => {
|
||||
const autoCleanup = withAbortSignalForEachTest();
|
||||
const page = {
|
||||
id: 'page1',
|
||||
app: 'bar-app',
|
||||
title: 'bar-title',
|
||||
vm: 'bar-vm',
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('middleware is created with device, debugger, and page information', async () => {
|
||||
const createCustomMessageHandler = jest.fn().mockImplementation(() => null);
|
||||
const {server} = await createServer({
|
||||
logger: undefined,
|
||||
projectRoot: '',
|
||||
unstable_customInspectorMessageHandler: createCustomMessageHandler,
|
||||
});
|
||||
|
||||
let device, debugger_;
|
||||
try {
|
||||
({device, debugger_} = await createAndConnectTarget(
|
||||
serverRefUrls(server),
|
||||
autoCleanup.signal,
|
||||
page,
|
||||
));
|
||||
|
||||
// Ensure the middleware was created with the device information
|
||||
await until(() =>
|
||||
expect(createCustomMessageHandler).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
page: expect.objectContaining({
|
||||
...page,
|
||||
capabilities: expect.any(Object),
|
||||
}),
|
||||
device: expect.objectContaining({
|
||||
appId: expect.any(String),
|
||||
id: expect.any(String),
|
||||
name: expect.any(String),
|
||||
sendMessage: expect.any(Function),
|
||||
}),
|
||||
debugger: expect.objectContaining({
|
||||
userAgent: null,
|
||||
sendMessage: expect.any(Function),
|
||||
}),
|
||||
}),
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
device?.close();
|
||||
debugger_?.close();
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
test('send message functions are passing messages to sockets', async () => {
|
||||
const handleDebuggerMessage = jest.fn();
|
||||
const handleDeviceMessage = jest.fn();
|
||||
const createCustomMessageHandler = jest.fn().mockImplementation(() => ({
|
||||
handleDebuggerMessage,
|
||||
handleDeviceMessage,
|
||||
}));
|
||||
|
||||
const {server} = await createServer({
|
||||
logger: undefined,
|
||||
projectRoot: '',
|
||||
unstable_customInspectorMessageHandler: createCustomMessageHandler,
|
||||
});
|
||||
|
||||
let device, debugger_;
|
||||
try {
|
||||
({device, debugger_} = await createAndConnectTarget(
|
||||
serverRefUrls(server),
|
||||
autoCleanup.signal,
|
||||
page,
|
||||
));
|
||||
|
||||
// Ensure the middleware was created with the send message methods
|
||||
await until(() =>
|
||||
expect(createCustomMessageHandler).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
device: expect.objectContaining({
|
||||
sendMessage: expect.any(Function),
|
||||
}),
|
||||
debugger: expect.objectContaining({
|
||||
sendMessage: expect.any(Function),
|
||||
}),
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
// Send a message to the device
|
||||
createCustomMessageHandler.mock.calls[0][0].device.sendMessage({
|
||||
id: 1,
|
||||
});
|
||||
// Ensure the device received the message
|
||||
await until(() =>
|
||||
expect(device.wrappedEvent).toBeCalledWith({
|
||||
event: 'wrappedEvent',
|
||||
payload: {
|
||||
pageId: page.id,
|
||||
wrappedEvent: JSON.stringify({id: 1}),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
// Send a message to the debugger
|
||||
createCustomMessageHandler.mock.calls[0][0].debugger.sendMessage({
|
||||
id: 2,
|
||||
});
|
||||
// Ensure the debugger received the message
|
||||
await until(() =>
|
||||
expect(debugger_.handle).toBeCalledWith({
|
||||
id: 2,
|
||||
}),
|
||||
);
|
||||
} finally {
|
||||
device?.close();
|
||||
debugger_?.close();
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
test('device message is passed to message middleware', async () => {
|
||||
const handleDeviceMessage = jest.fn();
|
||||
const {server} = await createServer({
|
||||
logger: undefined,
|
||||
projectRoot: '',
|
||||
unstable_customInspectorMessageHandler: () => ({
|
||||
handleDeviceMessage,
|
||||
handleDebuggerMessage() {},
|
||||
}),
|
||||
});
|
||||
|
||||
let device, debugger_;
|
||||
try {
|
||||
({device, debugger_} = await createAndConnectTarget(
|
||||
serverRefUrls(server),
|
||||
autoCleanup.signal,
|
||||
page,
|
||||
));
|
||||
|
||||
// Send a message from the device, and ensure the middleware received it
|
||||
device.sendWrappedEvent(page.id, {id: 1337});
|
||||
|
||||
// Ensure the debugger received the message
|
||||
await until(() => expect(debugger_.handle).toBeCalledWith({id: 1337}));
|
||||
// Ensure the middleware received the message
|
||||
await until(() => expect(handleDeviceMessage).toBeCalled());
|
||||
} finally {
|
||||
device?.close();
|
||||
debugger_?.close();
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
test('device message stops propagating when handled by middleware', async () => {
|
||||
const handleDeviceMessage = jest.fn();
|
||||
const {server} = await createServer({
|
||||
logger: undefined,
|
||||
projectRoot: '',
|
||||
unstable_customInspectorMessageHandler: () => ({
|
||||
handleDeviceMessage,
|
||||
handleDebuggerMessage() {},
|
||||
}),
|
||||
});
|
||||
|
||||
let device, debugger_;
|
||||
try {
|
||||
({device, debugger_} = await createAndConnectTarget(
|
||||
serverRefUrls(server),
|
||||
autoCleanup.signal,
|
||||
page,
|
||||
));
|
||||
|
||||
// Stop the first message from propagating by returning true (once) from middleware
|
||||
handleDeviceMessage.mockReturnValueOnce(true);
|
||||
|
||||
// Send the first message which should NOT be received by the debugger
|
||||
device.sendWrappedEvent(page.id, {id: -1});
|
||||
await until(() => expect(handleDeviceMessage).toBeCalled());
|
||||
|
||||
// Send the second message which should be received by the debugger
|
||||
device.sendWrappedEvent(page.id, {id: 1337});
|
||||
|
||||
// Ensure only the last message was received by the debugger
|
||||
await until(() => expect(debugger_.handle).toBeCalledWith({id: 1337}));
|
||||
// Ensure the first message was not received by the debugger
|
||||
expect(debugger_.handle).not.toBeCalledWith({id: -1});
|
||||
} finally {
|
||||
device?.close();
|
||||
debugger_?.close();
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
test('debugger message is passed to message middleware', async () => {
|
||||
const handleDebuggerMessage = jest.fn();
|
||||
const {server} = await createServer({
|
||||
logger: undefined,
|
||||
projectRoot: '',
|
||||
unstable_customInspectorMessageHandler: () => ({
|
||||
handleDeviceMessage() {},
|
||||
handleDebuggerMessage,
|
||||
}),
|
||||
});
|
||||
|
||||
let device, debugger_;
|
||||
try {
|
||||
({device, debugger_} = await createAndConnectTarget(
|
||||
serverRefUrls(server),
|
||||
autoCleanup.signal,
|
||||
page,
|
||||
));
|
||||
|
||||
// Send a message from the debugger
|
||||
const message = {
|
||||
method: 'Runtime.enable',
|
||||
id: 1337,
|
||||
};
|
||||
debugger_.send(message);
|
||||
|
||||
// Ensure the device received the message
|
||||
await until(() => expect(device.wrappedEvent).toBeCalled());
|
||||
// Ensure the middleware received the message
|
||||
await until(() => expect(handleDebuggerMessage).toBeCalledWith(message));
|
||||
} finally {
|
||||
device?.close();
|
||||
debugger_?.close();
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
test('debugger message stops propagating when handled by middleware', async () => {
|
||||
const handleDebuggerMessage = jest.fn();
|
||||
const {server} = await createServer({
|
||||
logger: undefined,
|
||||
projectRoot: '',
|
||||
unstable_customInspectorMessageHandler: () => ({
|
||||
handleDeviceMessage() {},
|
||||
handleDebuggerMessage,
|
||||
}),
|
||||
});
|
||||
|
||||
let device, debugger_;
|
||||
try {
|
||||
({device, debugger_} = await createAndConnectTarget(
|
||||
serverRefUrls(server),
|
||||
autoCleanup.signal,
|
||||
page,
|
||||
));
|
||||
|
||||
// Stop the first message from propagating by returning true (once) from middleware
|
||||
handleDebuggerMessage.mockReturnValueOnce(true);
|
||||
|
||||
// Send the first emssage which should not be received by the device
|
||||
debugger_.send({id: -1});
|
||||
// Send the second message which should be received by the device
|
||||
debugger_.send({id: 1337});
|
||||
|
||||
// Ensure only the last message was received by the device
|
||||
await until(() =>
|
||||
expect(device.wrappedEvent).toBeCalledWith({
|
||||
event: 'wrappedEvent',
|
||||
payload: {pageId: page.id, wrappedEvent: JSON.stringify({id: 1337})},
|
||||
}),
|
||||
);
|
||||
// Ensure the first message was not received by the device
|
||||
expect(device.wrappedEvent).not.toBeCalledWith({id: -1});
|
||||
} finally {
|
||||
device?.close();
|
||||
debugger_?.close();
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function serverRefUrls(server: http$Server | https$Server) {
|
||||
return {
|
||||
serverBaseUrl: baseUrlForServer(server, 'http'),
|
||||
serverBaseWsUrl: baseUrlForServer(server, 'ws'),
|
||||
};
|
||||
}
|
||||
|
||||
async function closeServer(server: http$Server | https$Server): Promise<void> {
|
||||
return new Promise(resolve => server.close(() => resolve()));
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
* @oncall react_native
|
||||
*/
|
||||
|
||||
import type {CreateCustomMessageHandlerFn} from './inspector-proxy/CustomMessageHandler';
|
||||
import type {BrowserLauncher} from './types/BrowserLauncher';
|
||||
import type {EventReporter} from './types/EventReporter';
|
||||
import type {Experiments, ExperimentsConfig} from './types/Experiments';
|
||||
@@ -61,11 +62,12 @@ type Options = $ReadOnly<{
|
||||
unstable_experiments?: ExperimentsConfig,
|
||||
|
||||
/**
|
||||
* An interface for using a modified inspector proxy implementation.
|
||||
* Create custom handler to add support for unsupported CDP events, or debuggers.
|
||||
* This handler is instantiated per logical device and debugger pair.
|
||||
*
|
||||
* This is an unstable API with no semver guarantees.
|
||||
*/
|
||||
unstable_InspectorProxy?: Class<InspectorProxy>,
|
||||
unstable_customInspectorMessageHandler?: CreateCustomMessageHandlerFn,
|
||||
}>;
|
||||
|
||||
type DevMiddlewareAPI = $ReadOnly<{
|
||||
@@ -80,16 +82,16 @@ export default function createDevMiddleware({
|
||||
unstable_browserLauncher = DefaultBrowserLauncher,
|
||||
unstable_eventReporter,
|
||||
unstable_experiments: experimentConfig = {},
|
||||
unstable_InspectorProxy,
|
||||
unstable_customInspectorMessageHandler,
|
||||
}: Options): DevMiddlewareAPI {
|
||||
const experiments = getExperiments(experimentConfig);
|
||||
|
||||
const InspectorProxyClass = unstable_InspectorProxy ?? InspectorProxy;
|
||||
const inspectorProxy = new InspectorProxyClass(
|
||||
const inspectorProxy = new InspectorProxy(
|
||||
projectRoot,
|
||||
serverBaseUrl,
|
||||
unstable_eventReporter,
|
||||
experiments,
|
||||
unstable_customInspectorMessageHandler,
|
||||
);
|
||||
|
||||
const middleware = connect()
|
||||
|
||||
@@ -13,6 +13,8 @@ export {default as createDevMiddleware} from './createDevMiddleware';
|
||||
|
||||
export type {BrowserLauncher, LaunchedBrowser} from './types/BrowserLauncher';
|
||||
export type {EventReporter, ReportableEvent} from './types/EventReporter';
|
||||
|
||||
export {default as unstable_InspectorProxy} from './inspector-proxy/InspectorProxy';
|
||||
export {default as unstable_Device} from './inspector-proxy/Device';
|
||||
export type {
|
||||
CustomMessageHandler,
|
||||
CustomMessageHandlerConnection,
|
||||
CreateCustomMessageHandlerFn,
|
||||
} from './inspector-proxy/CustomMessageHandler';
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow strict-local
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {JSONSerializable, Page} from './types';
|
||||
|
||||
type ExposedDevice = $ReadOnly<{
|
||||
appId: string,
|
||||
id: string,
|
||||
name: string,
|
||||
sendMessage: (message: JSONSerializable) => void,
|
||||
}>;
|
||||
|
||||
type ExposedDebugger = $ReadOnly<{
|
||||
userAgent: string | null,
|
||||
sendMessage: (message: JSONSerializable) => void,
|
||||
}>;
|
||||
|
||||
export type CustomMessageHandlerConnection = $ReadOnly<{
|
||||
page: Page,
|
||||
device: ExposedDevice,
|
||||
debugger: ExposedDebugger,
|
||||
}>;
|
||||
|
||||
export type CreateCustomMessageHandlerFn = (
|
||||
connection: CustomMessageHandlerConnection,
|
||||
) => ?CustomMessageHandler;
|
||||
|
||||
/**
|
||||
* The device message middleware allows implementers to handle unsupported CDP messages.
|
||||
* It is instantiated per device and may contain state that is specific to that device.
|
||||
* The middleware can also mark messages from the device or debugger as handled, which stops propagating.
|
||||
*/
|
||||
export interface CustomMessageHandler {
|
||||
/**
|
||||
* Handle a CDP message coming from the device.
|
||||
* This is invoked before the message is sent to the debugger.
|
||||
* When returning true, the message is considered handled and will not be sent to the debugger.
|
||||
*/
|
||||
handleDeviceMessage(message: JSONSerializable): true | void;
|
||||
|
||||
/**
|
||||
* Handle a CDP message coming from the debugger.
|
||||
* This is invoked before the message is sent to the device.
|
||||
* When returning true, the message is considered handled and will not be sent to the device.
|
||||
*/
|
||||
handleDebuggerMessage(message: JSONSerializable): true | void;
|
||||
}
|
||||
@@ -16,6 +16,10 @@ import type {
|
||||
CDPResponse,
|
||||
CDPServerMessage,
|
||||
} from './cdp-types/messages';
|
||||
import type {
|
||||
CreateCustomMessageHandlerFn,
|
||||
CustomMessageHandler,
|
||||
} from './CustomMessageHandler';
|
||||
import type {
|
||||
MessageFromDevice,
|
||||
MessageToDevice,
|
||||
@@ -51,6 +55,11 @@ type DebuggerInfo = {
|
||||
userAgent: string | null,
|
||||
};
|
||||
|
||||
type DebuggerConnection = {
|
||||
...DebuggerInfo,
|
||||
customHandler: ?CustomMessageHandler,
|
||||
};
|
||||
|
||||
const REACT_NATIVE_RELOADABLE_PAGE_ID = '-1';
|
||||
|
||||
/**
|
||||
@@ -74,7 +83,7 @@ export default class Device {
|
||||
#pages: $ReadOnlyMap<string, Page>;
|
||||
|
||||
// Stores information about currently connected debugger (if any).
|
||||
#debuggerConnection: ?DebuggerInfo = null;
|
||||
#debuggerConnection: ?DebuggerConnection = null;
|
||||
|
||||
// Last known Page ID of the React Native page.
|
||||
// This is used by debugger connections that don't have PageID specified
|
||||
@@ -97,6 +106,9 @@ export default class Device {
|
||||
|
||||
#pagesPollingIntervalId: ReturnType<typeof setInterval>;
|
||||
|
||||
// The device message middleware factory function allowing implementers to handle unsupported CDP messages.
|
||||
#createCustomMessageHandler: ?CreateCustomMessageHandlerFn;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
name: string,
|
||||
@@ -104,6 +116,7 @@ export default class Device {
|
||||
socket: WS,
|
||||
projectRoot: string,
|
||||
eventReporter: ?EventReporter,
|
||||
createMessageMiddleware: ?CreateCustomMessageHandlerFn,
|
||||
) {
|
||||
this.#id = id;
|
||||
this.#name = name;
|
||||
@@ -118,6 +131,7 @@ export default class Device {
|
||||
appId: app,
|
||||
})
|
||||
: null;
|
||||
this.#createCustomMessageHandler = createMessageMiddleware;
|
||||
|
||||
// $FlowFixMe[incompatible-call]
|
||||
this.#deviceSocket.on('message', (message: string) => {
|
||||
@@ -205,6 +219,7 @@ export default class Device {
|
||||
prependedFilePrefix: false,
|
||||
pageId,
|
||||
userAgent: metadata.userAgent,
|
||||
customHandler: null,
|
||||
};
|
||||
|
||||
// TODO(moti): Handle null case explicitly, e.g. refuse to connect to
|
||||
@@ -215,6 +230,50 @@ export default class Device {
|
||||
|
||||
debug(`Got new debugger connection for page ${pageId} of ${this.#name}`);
|
||||
|
||||
if (page && this.#debuggerConnection && this.#createCustomMessageHandler) {
|
||||
this.#debuggerConnection.customHandler = this.#createCustomMessageHandler(
|
||||
{
|
||||
page,
|
||||
debugger: {
|
||||
userAgent: debuggerInfo.userAgent,
|
||||
sendMessage: message => {
|
||||
try {
|
||||
const payload = JSON.stringify(message);
|
||||
debug('(Debugger) <- (Proxy) (Device): ' + payload);
|
||||
socket.send(payload);
|
||||
} catch {}
|
||||
},
|
||||
},
|
||||
device: {
|
||||
appId: this.#app,
|
||||
id: this.#id,
|
||||
name: this.#name,
|
||||
sendMessage: message => {
|
||||
try {
|
||||
const payload = JSON.stringify({
|
||||
event: 'wrappedEvent',
|
||||
payload: {
|
||||
pageId: this.#mapToDevicePageId(pageId),
|
||||
wrappedEvent: JSON.stringify(message),
|
||||
},
|
||||
});
|
||||
debug('(Debugger) -> (Proxy) (Device): ' + payload);
|
||||
this.#deviceSocket.send(payload);
|
||||
} catch {}
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (this.#debuggerConnection.customHandler) {
|
||||
debug('Created new custom message handler for debugger connection');
|
||||
} else {
|
||||
debug(
|
||||
'Skipping new custom message handler for debugger connection, factory function returned null',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.#sendMessageToDevice({
|
||||
event: 'connect',
|
||||
payload: {
|
||||
@@ -231,6 +290,15 @@ export default class Device {
|
||||
frontendUserAgent: metadata.userAgent,
|
||||
});
|
||||
let processedReq = debuggerRequest;
|
||||
|
||||
if (
|
||||
this.#debuggerConnection?.customHandler?.handleDebuggerMessage(
|
||||
debuggerRequest,
|
||||
) === true
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!page || !this.#pageHasCapability(page, 'nativeSourceCodeFetching')) {
|
||||
processedReq = this.#interceptClientMessageForSourceFetching(
|
||||
debuggerRequest,
|
||||
@@ -411,12 +479,21 @@ export default class Device {
|
||||
});
|
||||
}
|
||||
|
||||
if (this.#debuggerConnection != null) {
|
||||
const debuggerConnection = this.#debuggerConnection;
|
||||
if (debuggerConnection != null) {
|
||||
if (
|
||||
debuggerConnection.customHandler?.handleDeviceMessage(
|
||||
parsedPayload,
|
||||
) === true
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wrapping just to make flow happy :)
|
||||
// $FlowFixMe[unused-promise]
|
||||
this.#processMessageFromDeviceLegacy(
|
||||
parsedPayload,
|
||||
this.#debuggerConnection,
|
||||
debuggerConnection,
|
||||
pageId,
|
||||
).then(() => {
|
||||
const messageToSend = JSON.stringify(parsedPayload);
|
||||
@@ -499,7 +576,7 @@ export default class Device {
|
||||
// Allows to make changes in incoming message from device.
|
||||
async #processMessageFromDeviceLegacy(
|
||||
payload: CDPServerMessage,
|
||||
debuggerInfo: DebuggerInfo,
|
||||
debuggerInfo: DebuggerConnection,
|
||||
pageId: ?string,
|
||||
) {
|
||||
// TODO(moti): Handle null case explicitly, or ideally associate a copy
|
||||
@@ -616,7 +693,7 @@ export default class Device {
|
||||
*/
|
||||
#interceptClientMessageForSourceFetching(
|
||||
req: CDPClientMessage,
|
||||
debuggerInfo: DebuggerInfo,
|
||||
debuggerInfo: DebuggerConnection,
|
||||
socket: WS,
|
||||
): CDPClientMessage | null {
|
||||
switch (req.method) {
|
||||
@@ -633,7 +710,7 @@ export default class Device {
|
||||
|
||||
#processDebuggerSetBreakpointByUrl(
|
||||
req: CDPRequest<'Debugger.setBreakpointByUrl'>,
|
||||
debuggerInfo: DebuggerInfo,
|
||||
debuggerInfo: DebuggerConnection,
|
||||
): CDPRequest<'Debugger.setBreakpointByUrl'> {
|
||||
// If we replaced Android emulator's address to localhost we need to change it back.
|
||||
if (debuggerInfo.originalSourceURLAddress != null) {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
import type {EventReporter} from '../types/EventReporter';
|
||||
import type {Experiments} from '../types/Experiments';
|
||||
import type {CreateCustomMessageHandlerFn} from './CustomMessageHandler';
|
||||
import type {
|
||||
JsonPagesListResponse,
|
||||
JsonVersionResponse,
|
||||
@@ -58,17 +59,22 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
|
||||
#experiments: Experiments;
|
||||
|
||||
// custom message handler factory allowing implementers to handle unsupported CDP messages.
|
||||
#customMessageHandler: ?CreateCustomMessageHandlerFn;
|
||||
|
||||
constructor(
|
||||
projectRoot: string,
|
||||
serverBaseUrl: string,
|
||||
eventReporter: ?EventReporter,
|
||||
experiments: Experiments,
|
||||
customMessageHandler: ?CreateCustomMessageHandlerFn,
|
||||
) {
|
||||
this.#projectRoot = projectRoot;
|
||||
this.#serverBaseUrl = serverBaseUrl;
|
||||
this.#devices = new Map();
|
||||
this.#eventReporter = eventReporter;
|
||||
this.#experiments = experiments;
|
||||
this.#customMessageHandler = customMessageHandler;
|
||||
}
|
||||
|
||||
getPageDescriptions(): Array<PageDescription> {
|
||||
@@ -204,6 +210,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
|
||||
socket,
|
||||
this.#projectRoot,
|
||||
this.#eventReporter,
|
||||
this.#customMessageHandler,
|
||||
);
|
||||
|
||||
if (oldDevice) {
|
||||
|
||||
Reference in New Issue
Block a user