Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve CDP Flow types #42816

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 33 additions & 26 deletions packages/dev-middleware/src/inspector-proxy/Device.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,11 @@

import type {EventReporter} from '../types/EventReporter';
import type {
DebuggerRequest,
ErrorResponse,
GetScriptSourceRequest,
GetScriptSourceResponse,
MessageFromDevice,
MessageToDevice,
Page,
SetBreakpointByUrlRequest,
} from './types';
CDPClientMessage,
CDPRequest,
CDPResponse,
} from './cdp-types/messages';
import type {MessageFromDevice, MessageToDevice, Page} from './types';

import DeviceEventReporter from './DeviceEventReporter';
import * as fs from 'fs';
Expand Down Expand Up @@ -581,27 +577,32 @@ export default class Device {
}
}

// Allows to make changes in incoming messages from debugger. Returns a boolean
// indicating whether the message has been handled locally (i.e. does not need
// to be forwarded to the target).
/**
* Intercept an incoming message from a connected debugger. Returns either an
* original/replacement CDP message object, or `null` (will forward nothing
* to the target).
*/
#interceptMessageFromDebuggerLegacy(
req: DebuggerRequest,
req: CDPClientMessage,
debuggerInfo: DebuggerInfo,
socket: WS,
): ?DebuggerRequest {
if (req.method === 'Debugger.setBreakpointByUrl') {
return this.#processDebuggerSetBreakpointByUrl(req, debuggerInfo);
} else if (req.method === 'Debugger.getScriptSource') {
this.#processDebuggerGetScriptSource(req, socket);
return null;
): CDPClientMessage | null {
switch (req.method) {
case 'Debugger.setBreakpointByUrl':
return this.#processDebuggerSetBreakpointByUrl(req, debuggerInfo);
case 'Debugger.getScriptSource':
// Sends response to debugger via side-effect
this.#processDebuggerGetScriptSource(req, socket);
return null;
default:
return req;
}
return req;
}

#processDebuggerSetBreakpointByUrl(
req: SetBreakpointByUrlRequest,
req: CDPRequest<'Debugger.setBreakpointByUrl'>,
debuggerInfo: DebuggerInfo,
): SetBreakpointByUrlRequest {
): CDPRequest<'Debugger.setBreakpointByUrl'> {
// If we replaced Android emulator's address to localhost we need to change it back.
if (debuggerInfo.originalSourceURLAddress != null) {
const processedReq = {...req, params: {...req.params}};
Expand Down Expand Up @@ -635,10 +636,16 @@ export default class Device {
return req;
}

#processDebuggerGetScriptSource(req: GetScriptSourceRequest, socket: WS) {
#processDebuggerGetScriptSource(
req: CDPRequest<'Debugger.getScriptSource'>,
socket: WS,
): void {
const sendSuccessResponse = (scriptSource: string) => {
const result: GetScriptSourceResponse = {scriptSource};
const response = {id: req.id, result};
const result = {scriptSource};
const response: CDPResponse<'Debugger.getScriptSource'> = {
id: req.id,
result,
};
socket.send(JSON.stringify(response));
this.#deviceEventReporter?.logResponse(response, 'proxy', {
pageId: this.#debuggerConnection?.pageId ?? null,
Expand All @@ -647,7 +654,7 @@ export default class Device {
};
const sendErrorResponse = (error: string) => {
// Tell the client that the request failed
const result: ErrorResponse = {error: {message: error}};
const result = {error: {message: error}};
const response = {id: req.id, result};
socket.send(JSON.stringify(response));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

import type {EventReporter} from '../types/EventReporter';
import type {CDPResponse} from './cdp-types/messages';

import TTLCache from '@isaacs/ttlcache';

Expand Down Expand Up @@ -69,11 +70,7 @@ class DeviceEventReporter {
}

logResponse(
res: $ReadOnly<{
id: number,
error?: {message: string, data?: mixed},
...
}>,
res: CDPResponse<>,
origin: 'device' | 'proxy',
metadata: $ReadOnly<{
pageId: string | null,
Expand Down
45 changes: 45 additions & 0 deletions packages/dev-middleware/src/inspector-proxy/cdp-types/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* 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 type {Commands, Events} from './protocol';

// Note: A CDP event is a JSON-RPC notification with no `id` member.
export type CDPEvent<TEvent: $Keys<Events> = 'unknown'> = $ReadOnly<{
method: TEvent,
params: Events[TEvent],
}>;

export type CDPRequest<TCommand: $Keys<Commands> = 'unknown'> = $ReadOnly<{
method: TCommand,
params: Commands[TCommand]['paramsType'],
id: number,
}>;

export type CDPResponse<TCommand: $Keys<Commands> = 'unknown'> =
| $ReadOnly<{
result: Commands[TCommand]['resultType'],
id: number,
}>
| $ReadOnly<{
error: CDPRequestError,
id: number,
}>;

export type CDPRequestError = $ReadOnly<{
code: number,
message: string,
data?: mixed,
}>;

export type CDPClientMessage =
| CDPRequest<'Debugger.getScriptSource'>
| CDPRequest<'Debugger.setBreakpointByUrl'>
| CDPRequest<>;
88 changes: 88 additions & 0 deletions packages/dev-middleware/src/inspector-proxy/cdp-types/protocol.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* 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
*/

// Adapted from https://github.com/ChromeDevTools/devtools-protocol/blob/master/types/protocol.d.ts

export interface Debugger {
GetScriptSourceParams: $ReadOnly<{
/**
* Id of the script to get source for.
*/
scriptId: string,
}>;

GetScriptSourceResult: $ReadOnly<{
/**
* Script source (empty in case of Wasm bytecode).
*/
scriptSource: string,

/**
* Wasm bytecode. (Encoded as a base64 string when passed over JSON)
*/
bytecode?: string,
}>;

SetBreakpointByUrlParams: $ReadOnly<{
/**
* Line number to set breakpoint at.
*/
lineNumber: number,

/**
* URL of the resources to set breakpoint on.
*/
url?: string,

/**
* Regex pattern for the URLs of the resources to set breakpoints on. Either `url` or
* `urlRegex` must be specified.
*/
urlRegex?: string,

/**
* Script hash of the resources to set breakpoint on.
*/
scriptHash?: string,

/**
* Offset in the line to set breakpoint at.
*/
columnNumber?: number,

/**
* Expression to use as a breakpoint condition. When specified, debugger will only stop on the
* breakpoint if this expression evaluates to true.
*/
condition?: string,
}>;
}

export type Events = {
[method: string]: mixed,
};

export type Commands = {
'Debugger.getScriptSource': {
paramsType: Debugger['GetScriptSourceParams'],
resultType: Debugger['GetScriptSourceResult'],
},

'Debugger.setBreakpointByUrl': {
paramsType: Debugger['SetBreakpointByUrlParams'],
resultType: void,
},

[method: string]: {
paramsType: mixed,
resultType: mixed,
},
};
43 changes: 0 additions & 43 deletions packages/dev-middleware/src/inspector-proxy/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,49 +95,6 @@ export type JsonVersionResponse = $ReadOnly<{
'Protocol-Version': string,
}>;

/**
* Types were exported from https://github.com/ChromeDevTools/devtools-protocol/blob/master/types/protocol.d.ts
*/

export type SetBreakpointByUrlRequest = $ReadOnly<{
id: number,
method: 'Debugger.setBreakpointByUrl',
params: $ReadOnly<{
lineNumber: number,
url?: string,
urlRegex?: string,
scriptHash?: string,
columnNumber?: number,
condition?: string,
}>,
}>;

export type GetScriptSourceRequest = $ReadOnly<{
id: number,
method: 'Debugger.getScriptSource',
params: {
scriptId: string,
},
}>;

export type GetScriptSourceResponse = $ReadOnly<{
scriptSource: string,
/**
* Wasm bytecode.
*/
bytecode?: string,
}>;

export type ErrorResponse = $ReadOnly<{
error: $ReadOnly<{
message: string,
}>,
}>;

export type DebuggerRequest =
| SetBreakpointByUrlRequest
| GetScriptSourceRequest;

export type JSONSerializable =
| boolean
| number
Expand Down
Loading