chrome-devtools-mcp 0.8.1 → 0.10.0

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 (118) hide show
  1. package/README.md +69 -9
  2. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Console.js +1 -8
  3. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Gzip.js +8 -6
  4. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ParsedURL.js +10 -20
  5. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/SegmentedRange.js +1 -2
  6. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Settings.js +4 -1
  7. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/StringOutputStream.js +1 -4
  8. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Worker.js +10 -2
  9. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/AidaClient.js +19 -0
  10. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/DispatchHttpRequestClient.js +54 -0
  11. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/GdpClient.js +6 -51
  12. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/InspectorFrontendHost.js +2 -2
  13. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/InspectorFrontendHostAPI.js +32 -29
  14. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/UserMetrics.js +15 -6
  15. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/host.js +2 -1
  16. package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/ArrayUtilities.js +1 -1
  17. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/CDPConnection.js +17 -0
  18. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/ConnectionTransport.js +12 -0
  19. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/InspectorBackend.js +81 -213
  20. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/protocol_client.js +3 -8
  21. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/AnimationModel.js +1 -2
  22. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMatchedStyles.js +45 -10
  23. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSModel.js +1 -1
  24. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSProperty.js +3 -6
  25. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSPropertyParserMatchers.js +14 -10
  26. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSRule.js +34 -6
  27. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSStyleDeclaration.js +4 -4
  28. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ChildTargetManager.js +8 -33
  29. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/Connections.js +10 -47
  30. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DOMModel.js +4 -0
  31. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DebuggerModel.js +3 -3
  32. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/EnhancedTracesParser.js +17 -3
  33. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkManager.js +371 -53
  34. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkRequest.js +5 -0
  35. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/PreloadingModel.js +56 -13
  36. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RehydratingConnection.js +133 -10
  37. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ResourceTreeModel.js +1 -1
  38. package/build/node_modules/chrome-devtools-frontend/front_end/{models/source_map_scopes → core/sdk}/ScopeTreeCache.js +9 -5
  39. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMap.js +50 -14
  40. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapManager.js +8 -2
  41. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapScopesInfo.js +131 -8
  42. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TargetManager.js +0 -21
  43. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TraceObject.js +9 -6
  44. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/sdk-meta.js +8 -1
  45. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/sdk.js +2 -1
  46. package/build/node_modules/chrome-devtools-frontend/front_end/generated/ARIAProperties.js +1301 -174
  47. package/build/node_modules/chrome-devtools-frontend/front_end/generated/Deprecation.js +7 -0
  48. package/build/node_modules/chrome-devtools-frontend/front_end/generated/InspectorBackendCommands.js +9 -45
  49. package/build/node_modules/chrome-devtools-frontend/front_end/generated/SupportedCSSProperties.js +74 -19
  50. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.js +50 -34
  51. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.js +46 -45
  52. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AICallTree.js +2 -3
  53. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AIContext.js +10 -25
  54. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CompilerScriptMapping.js +45 -2
  55. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/DebuggerWorkspaceBinding.js +1 -1
  56. package/build/node_modules/chrome-devtools-frontend/front_end/models/cpu_profile/ProfileTreeModel.js +6 -7
  57. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +14 -0
  58. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/NamesResolver.js +5 -11
  59. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/source_map_scopes.js +1 -2
  60. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceModel.js +1 -1
  61. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/Trie.js +8 -0
  62. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/ModelImpl.js +6 -3
  63. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/TraceTree.js +10 -3
  64. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/MetaHandler.js +4 -1
  65. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/NetworkRequestsHandler.js +12 -3
  66. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/UserTimingsHandler.js +1 -1
  67. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/CLSCulprits.js +2 -1
  68. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Cache.js +2 -1
  69. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DOMSize.js +2 -1
  70. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DocumentLatency.js +2 -1
  71. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DuplicatedJavaScript.js +2 -1
  72. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/FontDisplay.js +2 -1
  73. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ForcedReflow.js +3 -2
  74. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/INPBreakdown.js +2 -1
  75. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ImageDelivery.js +2 -1
  76. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +2 -1
  77. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPDiscovery.js +2 -1
  78. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LegacyJavaScript.js +2 -1
  79. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ModernHTTP.js +2 -1
  80. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +2 -1
  81. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/RenderBlocking.js +2 -1
  82. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/SlowCSSSelector.js +2 -1
  83. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ThirdParties.js +2 -1
  84. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Viewport.js +2 -1
  85. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/types/TraceEvents.js +3 -0
  86. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace_source_maps_resolver/SourceMapsResolver.js +1 -1
  87. package/build/node_modules/chrome-devtools-frontend/mcp/mcp.js +14 -0
  88. package/build/src/DevToolsConnectionAdapter.js +33 -0
  89. package/build/src/DevtoolsUtils.js +44 -0
  90. package/build/src/McpContext.js +182 -33
  91. package/build/src/McpResponse.js +169 -57
  92. package/build/src/PageCollector.js +123 -27
  93. package/build/src/WaitForHelper.js +5 -0
  94. package/build/src/browser.js +24 -12
  95. package/build/src/cli.js +87 -6
  96. package/build/src/formatters/consoleFormatter.js +29 -62
  97. package/build/src/formatters/networkFormatter.js +5 -6
  98. package/build/src/formatters/snapshotFormatter.js +28 -11
  99. package/build/src/logger.js +1 -1
  100. package/build/src/main.js +24 -6
  101. package/build/src/polyfill.js +2 -2
  102. package/build/src/third_party/THIRD_PARTY_NOTICES +1413 -0
  103. package/build/src/third_party/index.js +82791 -0
  104. package/build/src/tools/ToolDefinition.js +2 -2
  105. package/build/src/tools/categories.js +17 -9
  106. package/build/src/tools/console.js +71 -6
  107. package/build/src/tools/emulation.js +40 -48
  108. package/build/src/tools/input.js +57 -27
  109. package/build/src/tools/network.js +43 -13
  110. package/build/src/tools/pages.js +75 -49
  111. package/build/src/tools/performance.js +13 -10
  112. package/build/src/tools/screenshot.js +10 -9
  113. package/build/src/tools/script.js +29 -15
  114. package/build/src/tools/snapshot.js +27 -23
  115. package/build/src/trace-processing/parse.js +6 -16
  116. package/build/src/utils/keyboard.js +291 -0
  117. package/build/src/utils/types.js +6 -0
  118. package/package.json +16 -12
@@ -2,11 +2,12 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
  import * as AidaClient from './AidaClient.js';
5
+ import * as DispatchHttpRequestClient from './DispatchHttpRequestClient.js';
5
6
  import * as GdpClient from './GdpClient.js';
6
7
  import * as InspectorFrontendHost from './InspectorFrontendHost.js';
7
8
  import * as InspectorFrontendHostAPI from './InspectorFrontendHostAPI.js';
8
9
  import * as Platform from './Platform.js';
9
10
  import * as ResourceLoader from './ResourceLoader.js';
10
11
  import * as UserMetrics from './UserMetrics.js';
11
- export { AidaClient, GdpClient, InspectorFrontendHost, InspectorFrontendHostAPI, Platform, ResourceLoader, UserMetrics, };
12
+ export { AidaClient, DispatchHttpRequestClient, GdpClient, InspectorFrontendHost, InspectorFrontendHostAPI, Platform, ResourceLoader, UserMetrics, };
12
13
  export const userMetrics = new UserMetrics.UserMetrics();
@@ -18,7 +18,7 @@ export const removeElement = (array, element, firstOnly) => {
18
18
  array.length = index;
19
19
  return true;
20
20
  };
21
- function swap(array, i1, i2) {
21
+ export function swap(array, i1, i2) {
22
22
  const temp = array[i1];
23
23
  array[i1] = array[i2];
24
24
  array[i2] = temp;
@@ -0,0 +1,17 @@
1
+ // Copyright 2025 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+ /**
5
+ * Keep this in sync with https://source.chromium.org/chromium/chromium/src/+/main:third_party/inspector_protocol/crdtp/dispatch.h.
6
+ */
7
+ export var CDPErrorStatus;
8
+ (function (CDPErrorStatus) {
9
+ CDPErrorStatus[CDPErrorStatus["PARSE_ERROR"] = -32700] = "PARSE_ERROR";
10
+ CDPErrorStatus[CDPErrorStatus["INVALID_REQUEST"] = -32600] = "INVALID_REQUEST";
11
+ CDPErrorStatus[CDPErrorStatus["METHOD_NOT_FOUND"] = -32601] = "METHOD_NOT_FOUND";
12
+ CDPErrorStatus[CDPErrorStatus["INVALID_PARAMS"] = -32602] = "INVALID_PARAMS";
13
+ CDPErrorStatus[CDPErrorStatus["INTERNAL_ERROR"] = -32603] = "INTERNAL_ERROR";
14
+ CDPErrorStatus[CDPErrorStatus["SERVER_ERROR"] = -32000] = "SERVER_ERROR";
15
+ CDPErrorStatus[CDPErrorStatus["SESSION_NOT_FOUND"] = -32001] = "SESSION_NOT_FOUND";
16
+ CDPErrorStatus[CDPErrorStatus["DEVTOOLS_STUB_ERROR"] = -32015] = "DEVTOOLS_STUB_ERROR";
17
+ })(CDPErrorStatus || (CDPErrorStatus = {}));
@@ -0,0 +1,12 @@
1
+ // Copyright 2025 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+ let connectionFactory;
5
+ export class ConnectionTransport {
6
+ static setFactory(factory) {
7
+ connectionFactory = factory;
8
+ }
9
+ static getFactory() {
10
+ return connectionFactory;
11
+ }
12
+ }
@@ -1,12 +1,10 @@
1
1
  // Copyright 2011 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
+ import * as InspectorBackendCommands from '../../generated/InspectorBackendCommands.js';
5
+ import { CDPErrorStatus } from './CDPConnection.js';
6
+ import { ConnectionTransport } from './ConnectionTransport.js';
4
7
  import { NodeURL } from './NodeURL.js';
5
- export const DevToolsStubErrorCode = -32015;
6
- // TODO(dgozman): we are not reporting generic errors in tests, but we should
7
- // instead report them and just have some expected errors in test expectations.
8
- const GenericErrorCode = -32000;
9
- const ConnectionClosedErrorCode = -32001;
10
8
  export const splitQualifiedName = (string) => {
11
9
  const [domain, eventName] = string.split('.');
12
10
  return [domain, eventName];
@@ -16,10 +14,16 @@ export const qualifyName = (domain, name) => {
16
14
  };
17
15
  export class InspectorBackend {
18
16
  agentPrototypes = new Map();
19
- #initialized = false;
20
17
  #eventParameterNamesForDomain = new Map();
21
18
  typeMap = new Map();
22
19
  enumMap = new Map();
20
+ constructor() {
21
+ // Create the global here because registering commands will involve putting
22
+ // items onto the global.
23
+ // @ts-expect-error Global namespace instantiation
24
+ globalThis.Protocol ||= {};
25
+ InspectorBackendCommands.registerCommands(this);
26
+ }
23
27
  getOrCreateEventParameterNamesForDomain(domain) {
24
28
  let map = this.#eventParameterNamesForDomain.get(domain);
25
29
  if (!map) {
@@ -40,9 +44,6 @@ export class InspectorBackend {
40
44
  static reportProtocolWarning(error, messageObject) {
41
45
  console.warn(error + ': ' + JSON.stringify(messageObject));
42
46
  }
43
- isInitialized() {
44
- return this.#initialized;
45
- }
46
47
  agentPrototype(domain) {
47
48
  let prototype = this.agentPrototypes.get(domain);
48
49
  if (!prototype) {
@@ -54,7 +55,6 @@ export class InspectorBackend {
54
55
  registerCommand(method, parameters, replyArgs, description) {
55
56
  const [domain, command] = splitQualifiedName(method);
56
57
  this.agentPrototype(domain).registerCommand(command, parameters, replyArgs, description);
57
- this.#initialized = true;
58
58
  }
59
59
  registerEnum(type, values) {
60
60
  const [domain, name] = splitQualifiedName(type);
@@ -66,37 +66,14 @@ export class InspectorBackend {
66
66
  // @ts-expect-error globalThis global namespace pollution
67
67
  globalThis.Protocol[domain][name] = values;
68
68
  this.enumMap.set(type, values);
69
- this.#initialized = true;
70
69
  }
71
70
  registerType(method, parameters) {
72
71
  this.typeMap.set(method, parameters);
73
- this.#initialized = true;
74
72
  }
75
73
  registerEvent(eventName, params) {
76
74
  const domain = eventName.split('.')[0];
77
75
  const eventParameterNames = this.getOrCreateEventParameterNamesForDomain(domain);
78
76
  eventParameterNames.set(eventName, params);
79
- this.#initialized = true;
80
- }
81
- }
82
- let connectionFactory;
83
- export class Connection {
84
- // on message from browser
85
- setOnMessage(_onMessage) {
86
- }
87
- setOnDisconnect(_onDisconnect) {
88
- }
89
- // send raw CDP message to browser
90
- sendRawMessage(_message) {
91
- }
92
- disconnect() {
93
- throw new Error('not implemented');
94
- }
95
- static setFactory(factory) {
96
- connectionFactory = factory;
97
- }
98
- static getFactory() {
99
- return connectionFactory;
100
77
  }
101
78
  }
102
79
  export const test = {
@@ -136,6 +113,8 @@ export class SessionRouter {
136
113
  #pendingLongPollingMessageIds = new Set();
137
114
  #sessions = new Map();
138
115
  #pendingScripts = [];
116
+ #callbacks = new Map();
117
+ #observers = new Set();
139
118
  constructor(connection) {
140
119
  this.#connection = connection;
141
120
  test.deprecatedRunAfterPendingDispatches = this.deprecatedRunAfterPendingDispatches.bind(this);
@@ -146,45 +125,43 @@ export class SessionRouter {
146
125
  if (session) {
147
126
  session.target.dispose(reason);
148
127
  }
128
+ this.#observers.forEach(observer => observer.onDisconnect(reason));
149
129
  });
150
130
  }
151
- registerSession(target, sessionId, proxyConnection) {
152
- // Only the Audits panel uses proxy connections. If it is ever possible to have multiple active at the
153
- // same time, it should be tested thoroughly.
154
- if (proxyConnection) {
155
- for (const session of this.#sessions.values()) {
156
- if (session.proxyConnection) {
157
- console.error('Multiple simultaneous proxy connections are currently unsupported');
158
- break;
159
- }
160
- }
161
- }
162
- this.#sessions.set(sessionId, { target, callbacks: new Map(), proxyConnection });
131
+ observe(observer) {
132
+ this.#observers.add(observer);
133
+ }
134
+ unobserve(observer) {
135
+ this.#observers.delete(observer);
136
+ }
137
+ registerSession(target, sessionId) {
138
+ this.#sessions.set(sessionId, { target });
163
139
  }
164
140
  unregisterSession(sessionId) {
165
141
  const session = this.#sessions.get(sessionId);
166
142
  if (!session) {
167
143
  return;
168
144
  }
169
- for (const callback of session.callbacks.values()) {
170
- SessionRouter.dispatchUnregisterSessionError(callback);
145
+ for (const { resolve, method, sessionId: callbackSessionId } of this.#callbacks.values()) {
146
+ if (sessionId !== callbackSessionId) {
147
+ continue;
148
+ }
149
+ resolve({
150
+ error: {
151
+ message: `Session is unregistering, can\'t dispatch pending call to ${method}`,
152
+ code: CDPErrorStatus.SESSION_NOT_FOUND,
153
+ }
154
+ });
171
155
  }
172
156
  this.#sessions.delete(sessionId);
173
157
  }
174
- getTargetBySessionId(sessionId) {
175
- const session = this.#sessions.get(sessionId ? sessionId : '');
176
- if (!session) {
177
- return null;
178
- }
179
- return session.target;
180
- }
181
158
  nextMessageId() {
182
159
  return this.#lastMessageId++;
183
160
  }
184
161
  connection() {
185
162
  return this.#connection;
186
163
  }
187
- sendMessage(sessionId, domain, method, params, callback) {
164
+ send(method, params, sessionId) {
188
165
  const messageId = this.nextMessageId();
189
166
  const messageObject = {
190
167
  id: messageId,
@@ -200,23 +177,28 @@ export class SessionRouter {
200
177
  test.dumpProtocol('frontend: ' + JSON.stringify(messageObject));
201
178
  }
202
179
  if (test.onMessageSent) {
180
+ const domain = method.split('.')[0];
203
181
  const paramsObject = JSON.parse(JSON.stringify(params || {}));
204
- test.onMessageSent({ domain, method, params: paramsObject, id: messageId, sessionId }, this.getTargetBySessionId(sessionId));
182
+ test.onMessageSent({ domain, method, params: paramsObject, id: messageId, sessionId });
205
183
  }
206
184
  ++this.#pendingResponsesCount;
207
185
  if (LongPollingMethods.has(method)) {
208
186
  this.#pendingLongPollingMessageIds.add(messageId);
209
187
  }
210
- const session = this.#sessions.get(sessionId);
211
- if (!session) {
212
- return;
213
- }
214
- session.callbacks.set(messageId, { callback, method });
215
- this.#connection.sendRawMessage(JSON.stringify(messageObject));
188
+ return new Promise(resolve => {
189
+ this.#callbacks.set(messageId, { resolve, method, sessionId });
190
+ this.#connection.sendRawMessage(JSON.stringify(messageObject));
191
+ });
216
192
  }
217
193
  sendRawMessageForTesting(method, params, callback, sessionId = '') {
218
- const domain = method.split('.')[0];
219
- this.sendMessage(sessionId, domain, method, params, callback || (() => { }));
194
+ void this.send(method, params, sessionId).then(response => {
195
+ if ('error' in response && response.error) {
196
+ callback?.(response.error, null);
197
+ }
198
+ else if ('result' in response) {
199
+ callback?.(null, response.result);
200
+ }
201
+ });
220
202
  }
221
203
  onMessage(message) {
222
204
  if (test.dumpProtocol) {
@@ -224,65 +206,35 @@ export class SessionRouter {
224
206
  }
225
207
  if (test.onMessageReceived) {
226
208
  const messageObjectCopy = JSON.parse((typeof message === 'string') ? message : JSON.stringify(message));
227
- test.onMessageReceived(messageObjectCopy, this.getTargetBySessionId(messageObjectCopy.sessionId));
209
+ test.onMessageReceived(messageObjectCopy);
228
210
  }
229
211
  const messageObject = ((typeof message === 'string') ? JSON.parse(message) : message);
230
- // Send all messages to proxy connections.
231
- let suppressUnknownMessageErrors = false;
232
- for (const session of this.#sessions.values()) {
233
- if (!session.proxyConnection) {
234
- continue;
235
- }
236
- if (!session.proxyConnection.onMessage) {
237
- InspectorBackend.reportProtocolError('Protocol Error: the session has a proxyConnection with no _onMessage', messageObject);
238
- continue;
239
- }
240
- session.proxyConnection.onMessage(messageObject);
241
- suppressUnknownMessageErrors = true;
242
- }
243
212
  const sessionId = messageObject.sessionId || '';
244
213
  const session = this.#sessions.get(sessionId);
245
- if (!session) {
246
- if (!suppressUnknownMessageErrors) {
247
- InspectorBackend.reportProtocolError('Protocol Error: the message with wrong session id', messageObject);
248
- }
249
- return;
250
- }
251
- // If this message is directly for the target controlled by the proxy connection, don't handle it.
252
- if (session.proxyConnection) {
253
- return;
254
- }
255
- if (session.target.getNeedsNodeJSPatching()) {
214
+ if (session?.target.getNeedsNodeJSPatching()) {
256
215
  NodeURL.patch(messageObject);
257
216
  }
258
- if (messageObject.id !== undefined) { // just a response for some request
259
- const callback = session.callbacks.get(messageObject.id);
260
- session.callbacks.delete(messageObject.id);
217
+ if ('id' in messageObject && messageObject.id !== undefined) { // just a response for some request
218
+ const callback = this.#callbacks.get(messageObject.id);
219
+ this.#callbacks.delete(messageObject.id);
261
220
  if (!callback) {
262
- if (messageObject.error?.code === ConnectionClosedErrorCode) {
263
- // Ignore the errors that are sent as responses after the session closes.
264
- return;
265
- }
266
- if (!suppressUnknownMessageErrors) {
267
- InspectorBackend.reportProtocolError('Protocol Error: the message with wrong id', messageObject);
268
- }
221
+ // Ignore messages with unknown IDs, we might see puppeteer proxied messages here.
269
222
  return;
270
223
  }
271
- callback.callback(messageObject.error || null, messageObject.result || null);
224
+ callback.resolve(messageObject);
272
225
  --this.#pendingResponsesCount;
273
226
  this.#pendingLongPollingMessageIds.delete(messageObject.id);
274
227
  if (this.#pendingScripts.length && !this.hasOutstandingNonLongPollingRequests()) {
275
228
  this.deprecatedRunAfterPendingDispatches();
276
229
  }
277
230
  }
278
- else {
279
- if (messageObject.method === undefined) {
280
- InspectorBackend.reportProtocolError('Protocol Error: the message without method', messageObject);
281
- return;
282
- }
231
+ else if ('method' in messageObject) {
283
232
  // This cast is justified as we just checked for the presence of messageObject.method.
284
- const eventMessage = messageObject;
285
- session.target.dispatch(eventMessage);
233
+ session?.target.dispatch(messageObject);
234
+ this.#observers.forEach(observer => observer.onEvent(messageObject));
235
+ }
236
+ else {
237
+ InspectorBackend.reportProtocolError('Protocol Error: the message without method', messageObject);
286
238
  }
287
239
  }
288
240
  hasOutstandingNonLongPollingRequests() {
@@ -311,22 +263,6 @@ export class SessionRouter {
311
263
  }
312
264
  }
313
265
  }
314
- static dispatchConnectionError(callback, method) {
315
- const error = {
316
- message: `Connection is closed, can\'t dispatch pending call to ${method}`,
317
- code: ConnectionClosedErrorCode,
318
- data: null,
319
- };
320
- window.setTimeout(() => callback(error, null), 0);
321
- }
322
- static dispatchUnregisterSessionError({ callback, method }) {
323
- const error = {
324
- message: `Session is unregistering, can\'t dispatch pending call to ${method}`,
325
- code: ConnectionClosedErrorCode,
326
- data: null,
327
- };
328
- window.setTimeout(() => callback(error, null), 0);
329
- }
330
266
  }
331
267
  export class TargetBase {
332
268
  needsNodeJSPatching;
@@ -337,18 +273,18 @@ export class TargetBase {
337
273
  constructor(needsNodeJSPatching, parentTarget, sessionId, connection) {
338
274
  this.needsNodeJSPatching = needsNodeJSPatching;
339
275
  this.sessionId = sessionId;
340
- if ((!parentTarget && connection) || (!parentTarget && sessionId) || (connection && sessionId)) {
341
- throw new Error('Either connection or sessionId (but not both) must be supplied for a child target');
276
+ if (parentTarget && !sessionId) {
277
+ throw new Error('Specifying a parent target requires a session ID');
342
278
  }
343
279
  let router;
344
- if (sessionId && parentTarget && parentTarget.#router) {
280
+ if (parentTarget && parentTarget.#router) {
345
281
  router = parentTarget.#router;
346
282
  }
347
283
  else if (connection) {
348
284
  router = new SessionRouter(connection);
349
285
  }
350
286
  else {
351
- router = new SessionRouter(connectionFactory());
287
+ router = new SessionRouter(ConnectionTransport.getFactory()());
352
288
  }
353
289
  this.#router = router;
354
290
  router.registerSession(this, this.sessionId);
@@ -638,6 +574,12 @@ export class TargetBase {
638
574
  return this.needsNodeJSPatching;
639
575
  }
640
576
  }
577
+ /** These are not logged as console.error */
578
+ const IGNORED_ERRORS = new Set([
579
+ CDPErrorStatus.DEVTOOLS_STUB_ERROR,
580
+ CDPErrorStatus.SERVER_ERROR,
581
+ CDPErrorStatus.SESSION_NOT_FOUND,
582
+ ]);
641
583
  /**
642
584
  * This is a class that serves as the prototype for a domains #agents (every target
643
585
  * has it's own set of #agents). The InspectorBackend keeps an instance of this class
@@ -648,113 +590,39 @@ export class TargetBase {
648
590
  * of the invoke_enable, etc. methods that the front-end uses.
649
591
  */
650
592
  class AgentPrototype {
651
- replyArgs;
652
593
  description = '';
653
594
  metadata;
654
595
  domain;
655
596
  target;
656
597
  constructor(domain) {
657
- this.replyArgs = {};
658
598
  this.domain = domain;
659
599
  this.metadata = {};
660
600
  }
661
601
  registerCommand(methodName, parameters, replyArgs, description) {
662
602
  const domainAndMethod = qualifyName(this.domain, methodName);
663
- function sendMessagePromise(...args) {
664
- return AgentPrototype.prototype.sendMessageToBackendPromise.call(this, domainAndMethod, parameters, args);
665
- }
666
- // @ts-expect-error Method code generation
667
- this[methodName] = sendMessagePromise;
668
603
  this.metadata[domainAndMethod] = { parameters, description, replyArgs };
669
604
  function invoke(request = {}) {
670
605
  return this.invoke(domainAndMethod, request);
671
606
  }
672
607
  // @ts-expect-error Method code generation
673
608
  this['invoke_' + methodName] = invoke;
674
- this.replyArgs[domainAndMethod] = replyArgs;
675
- }
676
- prepareParameters(method, parameters, args, errorCallback) {
677
- const params = {};
678
- let hasParams = false;
679
- for (const param of parameters) {
680
- const paramName = param.name;
681
- const typeName = param.type;
682
- const optionalFlag = param.optional;
683
- if (!args.length && !optionalFlag) {
684
- errorCallback(`Protocol Error: Invalid number of arguments for method '${method}' call. ` +
685
- `It must have the following arguments ${JSON.stringify(parameters)}'.`);
686
- return null;
687
- }
688
- const value = args.shift();
689
- if (optionalFlag && typeof value === 'undefined') {
690
- continue;
691
- }
692
- const expectedJSType = typeName === 'array' ? 'object' : typeName;
693
- if (typeof value !== expectedJSType) {
694
- errorCallback(`Protocol Error: Invalid type of argument '${paramName}' for method '${method}' call. ` +
695
- `It must be '${typeName}' but it is '${typeof value}'.`);
696
- return null;
697
- }
698
- params[paramName] = value;
699
- hasParams = true;
700
- }
701
- if (args.length) {
702
- errorCallback(`Protocol Error: Extra ${args.length} arguments in a call to method '${method}'.`);
703
- return null;
704
- }
705
- return hasParams ? params : null;
706
- }
707
- sendMessageToBackendPromise(method, parameters, args) {
708
- let errorMessage;
709
- function onError(message) {
710
- console.error(message);
711
- errorMessage = message;
712
- }
713
- const params = this.prepareParameters(method, parameters, args, onError);
714
- if (errorMessage) {
715
- return Promise.resolve(null);
716
- }
717
- return new Promise(resolve => {
718
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
719
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
720
- const callback = (error, result) => {
721
- if (error) {
722
- if (!test.suppressRequestErrors && error.code !== DevToolsStubErrorCode && error.code !== GenericErrorCode &&
723
- error.code !== ConnectionClosedErrorCode) {
724
- console.error('Request ' + method + ' failed. ' + JSON.stringify(error));
725
- }
726
- resolve(null);
727
- return;
728
- }
729
- const args = this.replyArgs[method];
730
- resolve(result && args.length ? result[args[0]] : undefined);
731
- };
732
- const router = this.target.router();
733
- if (!router) {
734
- SessionRouter.dispatchConnectionError(callback, method);
735
- }
736
- else {
737
- router.sendMessage(this.target.sessionId, this.domain, method, params, callback);
738
- }
739
- });
740
609
  }
741
610
  invoke(method, request) {
742
- return new Promise(fulfill => {
743
- const callback = (error, result) => {
744
- if (error && !test.suppressRequestErrors && error.code !== DevToolsStubErrorCode &&
745
- error.code !== GenericErrorCode && error.code !== ConnectionClosedErrorCode) {
746
- console.error('Request ' + method + ' failed. ' + JSON.stringify(error));
611
+ const router = this.target.router();
612
+ if (!router) {
613
+ return Promise.resolve({ result: null, getError: () => `Connection is closed, can\'t dispatch pending call to ${method}` });
614
+ }
615
+ return router.send(method, request, this.target.sessionId).then(response => {
616
+ if ('error' in response && response.error) {
617
+ if (!test.suppressRequestErrors && !IGNORED_ERRORS.has(response.error.code)) {
618
+ console.error('Request ' + method + ' failed. ' + JSON.stringify(response.error));
747
619
  }
748
- const errorMessage = error?.message;
749
- fulfill({ ...result, getError: () => errorMessage });
750
- };
751
- const router = this.target.router();
752
- if (!router) {
753
- SessionRouter.dispatchConnectionError(callback, method);
620
+ return { getError: () => response.error.message };
754
621
  }
755
- else {
756
- router.sendMessage(this.target.sessionId, this.domain, method, request, callback);
622
+ if ('result' in response) {
623
+ return { ...response.result, getError: () => undefined };
757
624
  }
625
+ return { getError: () => undefined };
758
626
  });
759
627
  }
760
628
  }
@@ -1,13 +1,8 @@
1
1
  // Copyright 2019 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
- import * as InspectorBackendCommands from '../../generated/InspectorBackendCommands.js';
4
+ import * as CDPConnection from './CDPConnection.js';
5
+ import * as ConnectionTransport from './ConnectionTransport.js';
5
6
  import * as InspectorBackend from './InspectorBackend.js';
6
7
  import * as NodeURL from './NodeURL.js';
7
- export { InspectorBackend, NodeURL, };
8
- // Create the global here because registering commands will involve putting
9
- // items onto the global.
10
- // @ts-expect-error Global namespace instantiation
11
-
12
- // FIXME: This instance of InspectorBackend should not be a side effect of importing this module.
13
-
8
+ export { CDPConnection, ConnectionTransport, InspectorBackend, NodeURL, };
@@ -678,12 +678,11 @@ export class AnimationGroup {
678
678
  #id;
679
679
  #scrollNode;
680
680
  #animations;
681
- #paused;
681
+ #paused = false;
682
682
  constructor(animationModel, id, animations) {
683
683
  this.#animationModel = animationModel;
684
684
  this.#id = id;
685
685
  this.#animations = animations;
686
- this.#paused = false;
687
686
  }
688
687
  isScrollDriven() {
689
688
  return Boolean(this.#animations[0]?.viewOrScrollTimeline());