chrome-devtools-frontend 1.0.1539728 → 1.0.1539972

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 (132) hide show
  1. package/front_end/core/common/Debouncer.ts +2 -2
  2. package/front_end/core/common/Gzip.ts +1 -1
  3. package/front_end/core/common/Throttler.ts +3 -3
  4. package/front_end/core/host/GdpClient.ts +4 -0
  5. package/front_end/core/protocol_client/DevToolsCDPConnection.ts +181 -0
  6. package/front_end/core/protocol_client/InspectorBackend.ts +36 -203
  7. package/front_end/core/protocol_client/protocol_client.ts +2 -2
  8. package/front_end/core/sdk/DebuggerModel.ts +3 -16
  9. package/front_end/core/sdk/RemoteObject.ts +4 -0
  10. package/front_end/core/sdk/Target.ts +3 -6
  11. package/front_end/core/sdk/TargetManager.ts +1 -2
  12. package/front_end/entrypoints/lighthouse_worker/LighthouseWorkerService.ts +1 -3
  13. package/front_end/entrypoints/node_app/app/NodeMain.ts +3 -2
  14. package/front_end/generated/Deprecation.ts +8 -0
  15. package/front_end/generated/InspectorBackendCommands.ts +2 -2
  16. package/front_end/generated/SupportedCSSProperties.js +50 -9
  17. package/front_end/generated/protocol.ts +2 -2
  18. package/front_end/models/ai_assistance/EvaluateAction.ts +88 -5
  19. package/front_end/models/ai_assistance/injected.ts +15 -2
  20. package/front_end/models/live-metrics/web-vitals-injected/README.md +1 -1
  21. package/front_end/models/trace/Styles.ts +1 -1
  22. package/front_end/panels/ai_assistance/PatchWidget.ts +22 -12
  23. package/front_end/panels/ai_assistance/components/ChatView.ts +1 -1
  24. package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +4 -4
  25. package/front_end/panels/common/AiCodeCompletionSummaryToolbar.ts +2 -2
  26. package/front_end/panels/elements/PropertiesWidget.ts +3 -2
  27. package/front_end/panels/event_listeners/EventListenersView.ts +9 -5
  28. package/front_end/panels/explain/components/ConsoleInsight.ts +2 -2
  29. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +3 -3
  30. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +2 -2
  31. package/front_end/panels/network/RequestPayloadView.ts +2 -1
  32. package/front_end/panels/network/RequestTimingView.ts +4 -2
  33. package/front_end/panels/network/components/RequestHeadersView.ts +24 -17
  34. package/front_end/panels/protocol_monitor/JSONEditor.ts +2 -2
  35. package/front_end/panels/recorder/RecorderController.ts +6 -7
  36. package/front_end/panels/recorder/models/RecordingPlayer.ts +3 -3
  37. package/front_end/panels/settings/components/SyncSection.ts +1 -1
  38. package/front_end/panels/sources/BreakpointsView.ts +3 -3
  39. package/front_end/panels/sources/ScopeChainSidebarPane.ts +4 -3
  40. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +3 -2
  41. package/front_end/panels/timeline/components/FieldSettingsDialog.ts +9 -5
  42. package/front_end/panels/timeline/components/LiveMetricsView.ts +20 -9
  43. package/front_end/panels/timeline/components/MetricCard.ts +4 -2
  44. package/front_end/services/puppeteer/PuppeteerConnection.ts +2 -1
  45. package/front_end/third_party/chromium/README.chromium +1 -1
  46. package/front_end/third_party/puppeteer/README.chromium +2 -2
  47. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +5 -0
  48. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  49. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  50. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts +1 -0
  51. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts.map +1 -1
  52. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js +3 -0
  53. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js.map +1 -1
  54. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts +1 -0
  55. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
  56. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +21 -0
  57. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
  58. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/ExtensionTransport.d.ts.map +1 -1
  59. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/ExtensionTransport.js +5 -1
  60. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/ExtensionTransport.js.map +1 -1
  61. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts +1 -0
  62. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +6 -0
  64. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  65. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.d.ts +1 -1
  66. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.d.ts.map +1 -1
  67. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.js +29 -27
  68. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.js.map +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  70. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  71. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  72. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  73. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +5 -0
  74. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +61 -26
  75. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +5 -0
  76. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  77. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts +1 -0
  79. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js +3 -0
  81. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts +1 -0
  83. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
  84. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +21 -0
  85. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
  86. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/ExtensionTransport.d.ts.map +1 -1
  87. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/ExtensionTransport.js +5 -1
  88. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/ExtensionTransport.js.map +1 -1
  89. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts +1 -0
  90. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +6 -0
  92. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  93. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.d.ts +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.d.ts.map +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.js +30 -28
  96. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.js.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  99. package/front_end/third_party/puppeteer/package/lib/types.d.ts +5 -0
  100. package/front_end/third_party/puppeteer/package/package.json +1 -1
  101. package/front_end/third_party/puppeteer/package/src/api/Page.ts +6 -0
  102. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +4 -0
  103. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +32 -0
  104. package/front_end/third_party/puppeteer/package/src/cdp/ExtensionTransport.ts +5 -1
  105. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +8 -0
  106. package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +36 -43
  107. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  108. package/front_end/ui/components/dialogs/ButtonDialog.ts +15 -5
  109. package/front_end/ui/components/expandable_list/ExpandableList.ts +1 -1
  110. package/front_end/ui/components/helpers/helpers.ts +0 -2
  111. package/front_end/ui/components/menus/Menu.ts +5 -3
  112. package/front_end/ui/components/survey_link/SurveyLink.docs.ts +22 -0
  113. package/front_end/ui/components/tree_outline/TreeOutline.ts +1 -2
  114. package/front_end/ui/legacy/SelectMenu.docs.ts +14 -0
  115. package/front_end/ui/legacy/components/object_ui/CustomPreviewComponent.ts +3 -1
  116. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +453 -347
  117. package/package.json +1 -1
  118. package/front_end/core/protocol_client/NodeURL.ts +0 -40
  119. package/front_end/ui/components/docs/combo_box/basic.html +0 -20
  120. package/front_end/ui/components/docs/combo_box/basic.ts +0 -49
  121. package/front_end/ui/components/docs/legacy_color_invert/basic.html +0 -77
  122. package/front_end/ui/components/docs/legacy_color_invert/basic.ts +0 -98
  123. package/front_end/ui/components/docs/survey_link/basic.html +0 -20
  124. package/front_end/ui/components/docs/survey_link/basic.ts +0 -28
  125. package/front_end/ui/components/docs/tree_outline/basic.html +0 -33
  126. package/front_end/ui/components/docs/tree_outline/basic.ts +0 -38
  127. package/front_end/ui/components/docs/tree_outline/custom-renderers.html +0 -32
  128. package/front_end/ui/components/docs/tree_outline/custom-renderers.ts +0 -61
  129. package/front_end/ui/components/docs/tree_outline/lazy-children.html +0 -32
  130. package/front_end/ui/components/docs/tree_outline/lazy-children.ts +0 -91
  131. package/front_end/ui/components/docs/tree_outline/sample-data.ts +0 -67
  132. package/front_end/ui/components/helpers/directives.ts +0 -38
@@ -6,10 +6,10 @@
6
6
  * Debounce utility function, ensures that the function passed in is only called once the function stops being called and the delay has expired.
7
7
  */
8
8
  export const debounce = function(func: (...args: any[]) => void, delay: number): (...args: any[]) => void {
9
- let timer = 0;
9
+ let timer: ReturnType<typeof setTimeout>;
10
10
  const debounced = (...args: any[]): void => {
11
11
  clearTimeout(timer);
12
- timer = window.setTimeout(() => func(...args), delay);
12
+ timer = setTimeout(() => func(...args), delay);
13
13
  };
14
14
  return debounced;
15
15
  };
@@ -54,7 +54,7 @@ async function gzipCodec(
54
54
  codecStream: CompressionStream|DecompressionStream): Promise<ArrayBuffer> {
55
55
  const readable = new ReadableStream({
56
56
  start(controller) {
57
- controller.enqueue(buffer);
57
+ controller.enqueue(buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : buffer);
58
58
  controller.close();
59
59
  }
60
60
  });
@@ -9,7 +9,7 @@ export class Throttler {
9
9
  #process: (() => (void|Promise<unknown>))|null;
10
10
  #lastCompleteTime: number;
11
11
  #scheduler = Promise.withResolvers<unknown>();
12
- #processTimeout?: number;
12
+ #processTimeout?: ReturnType<typeof setTimeout>;
13
13
 
14
14
  constructor(timeout: number) {
15
15
  this.#timeout = timeout;
@@ -78,11 +78,11 @@ export class Throttler {
78
78
  clearTimeout(this.#processTimeout);
79
79
 
80
80
  const timeout = this.#asSoonAsPossible ? 0 : this.#timeout;
81
- this.#processTimeout = window.setTimeout(this.#onTimeout.bind(this), timeout);
81
+ this.#processTimeout = setTimeout(this.#onTimeout.bind(this), timeout);
82
82
  }
83
83
 
84
84
  #getTime(): number {
85
- return window.performance.now();
85
+ return performance.now();
86
86
  }
87
87
  }
88
88
 
@@ -85,6 +85,7 @@ function normalizeBadgeName(name: string): string {
85
85
  }
86
86
 
87
87
  export const GOOGLE_DEVELOPER_PROGRAM_PROFILE_LINK = 'https://developers.google.com/profile/u/me';
88
+ const ORIGIN_APPLICATION_NAME = 'APPLICATION_CHROME_DEVTOOLS';
88
89
 
89
90
  async function makeHttpRequest<R>(request: DispatchHttpRequestRequest): Promise<R> {
90
91
  if (!isGdpProfilesAvailable()) {
@@ -208,6 +209,9 @@ export class GdpClient {
208
209
  body: JSON.stringify({
209
210
  user,
210
211
  newsletter_email: emailPreference,
212
+ creation_origin: {
213
+ origin_application: ORIGIN_APPLICATION_NAME,
214
+ }
211
215
  }),
212
216
  });
213
217
  this.#clearCache();
@@ -0,0 +1,181 @@
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
+ import {
6
+ type CDPCommandRequest,
7
+ type CDPConnection,
8
+ type CDPConnectionObserver,
9
+ type CDPError,
10
+ CDPErrorStatus,
11
+ type CDPReceivableMessage,
12
+ type Command,
13
+ type CommandParams,
14
+ type CommandResult
15
+ } from './CDPConnection.js';
16
+ import type {ConnectionTransport} from './ConnectionTransport.js';
17
+ import {InspectorBackend, type MessageError, type QualifiedName, test} from './InspectorBackend.js';
18
+
19
+ interface CallbackWithDebugInfo {
20
+ resolve: (response: Awaited<ReturnType<CDPConnection['send']>>) => void;
21
+ method: string;
22
+ sessionId: string|undefined;
23
+ }
24
+
25
+ type Callback = (error: MessageError|null, arg1: Object|null) => void;
26
+
27
+ const LongPollingMethods = new Set<string>(['CSS.takeComputedStyleUpdates']);
28
+
29
+ export class DevToolsCDPConnection implements CDPConnection {
30
+ readonly #transport: ConnectionTransport;
31
+ #lastMessageId = 1;
32
+ #pendingResponsesCount = 0;
33
+ readonly #pendingLongPollingMessageIds = new Set<number>();
34
+ #pendingScripts: Array<() => void> = [];
35
+ readonly #callbacks = new Map<number, CallbackWithDebugInfo>();
36
+ readonly #observers = new Set<CDPConnectionObserver>();
37
+
38
+ constructor(transport: ConnectionTransport) {
39
+ this.#transport = transport;
40
+
41
+ test.deprecatedRunAfterPendingDispatches = this.deprecatedRunAfterPendingDispatches.bind(this);
42
+ test.sendRawMessage = this.sendRawMessageForTesting.bind(this);
43
+
44
+ this.#transport.setOnMessage(this.onMessage.bind(this));
45
+ this.#transport.setOnDisconnect(reason => {
46
+ this.#observers.forEach(observer => observer.onDisconnect(reason));
47
+ });
48
+ }
49
+
50
+ observe(observer: CDPConnectionObserver): void {
51
+ this.#observers.add(observer);
52
+ }
53
+
54
+ unobserve(observer: CDPConnectionObserver): void {
55
+ this.#observers.delete(observer);
56
+ }
57
+
58
+ send<T extends Command>(method: T, params: CommandParams<T>, sessionId: string|undefined):
59
+ Promise<{result: CommandResult<T>}|{error: CDPError}> {
60
+ const messageId = ++this.#lastMessageId;
61
+ const messageObject: Partial<CDPCommandRequest<T>> = {
62
+ id: messageId,
63
+ method,
64
+ };
65
+
66
+ if (params) {
67
+ messageObject.params = params;
68
+ }
69
+ if (sessionId) {
70
+ messageObject.sessionId = sessionId;
71
+ }
72
+
73
+ if (test.dumpProtocol) {
74
+ test.dumpProtocol('frontend: ' + JSON.stringify(messageObject));
75
+ }
76
+
77
+ if (test.onMessageSent) {
78
+ const domain = method.split('.')[0];
79
+ const paramsObject = JSON.parse(JSON.stringify(params || {}));
80
+ test.onMessageSent({domain, method, params: (paramsObject as Object), id: messageId, sessionId});
81
+ }
82
+
83
+ ++this.#pendingResponsesCount;
84
+ if (LongPollingMethods.has(method)) {
85
+ this.#pendingLongPollingMessageIds.add(messageId);
86
+ }
87
+
88
+ return new Promise(resolve => {
89
+ this.#callbacks.set(messageId, {resolve, method, sessionId});
90
+ this.#transport.sendRawMessage(JSON.stringify(messageObject));
91
+ });
92
+ }
93
+
94
+ resolvePendingCalls(sessionId: string): void {
95
+ for (const {resolve, method, sessionId: callbackSessionId} of this.#callbacks.values()) {
96
+ if (sessionId !== callbackSessionId) {
97
+ continue;
98
+ }
99
+ resolve({
100
+ error: {
101
+ message: `Session is unregistering, can\'t dispatch pending call to ${method}`,
102
+ code: CDPErrorStatus.SESSION_NOT_FOUND,
103
+ }
104
+ });
105
+ }
106
+ }
107
+
108
+ private sendRawMessageForTesting(method: QualifiedName, params: Object|null, callback: Callback|null, sessionId = ''):
109
+ void {
110
+ void this.send(method as Command, params as CommandParams<Command>, sessionId).then(response => {
111
+ if ('error' in response && response.error) {
112
+ callback?.(response.error, null);
113
+ } else if ('result' in response) {
114
+ callback?.(null, response.result as Object | null);
115
+ }
116
+ });
117
+ }
118
+
119
+ private onMessage(message: string|Object): void {
120
+ if (test.dumpProtocol) {
121
+ test.dumpProtocol('backend: ' + ((typeof message === 'string') ? message : JSON.stringify(message)));
122
+ }
123
+
124
+ if (test.onMessageReceived) {
125
+ const messageObjectCopy = JSON.parse((typeof message === 'string') ? message : JSON.stringify(message));
126
+ test.onMessageReceived(messageObjectCopy);
127
+ }
128
+
129
+ const messageObject = ((typeof message === 'string') ? JSON.parse(message) : message) as CDPReceivableMessage;
130
+
131
+ if ('id' in messageObject && messageObject.id !== undefined) { // just a response for some request
132
+ const callback = this.#callbacks.get(messageObject.id);
133
+ this.#callbacks.delete(messageObject.id);
134
+ if (!callback) {
135
+ // Ignore messages with unknown IDs, we might see puppeteer proxied messages here.
136
+ return;
137
+ }
138
+
139
+ callback.resolve(messageObject);
140
+ --this.#pendingResponsesCount;
141
+ this.#pendingLongPollingMessageIds.delete(messageObject.id);
142
+
143
+ if (this.#pendingScripts.length && !this.hasOutstandingNonLongPollingRequests()) {
144
+ this.deprecatedRunAfterPendingDispatches();
145
+ }
146
+ } else if ('method' in messageObject) {
147
+ this.#observers.forEach(observer => observer.onEvent(messageObject));
148
+ } else {
149
+ InspectorBackend.reportProtocolError('Protocol Error: the message without method', messageObject);
150
+ }
151
+ }
152
+
153
+ private hasOutstandingNonLongPollingRequests(): boolean {
154
+ return this.#pendingResponsesCount - this.#pendingLongPollingMessageIds.size > 0;
155
+ }
156
+
157
+ private deprecatedRunAfterPendingDispatches(script?: (() => void)): void {
158
+ if (script) {
159
+ this.#pendingScripts.push(script);
160
+ }
161
+
162
+ // Execute all promises.
163
+ setTimeout(() => {
164
+ if (!this.hasOutstandingNonLongPollingRequests()) {
165
+ this.executeAfterPendingDispatches();
166
+ } else {
167
+ this.deprecatedRunAfterPendingDispatches();
168
+ }
169
+ }, 0);
170
+ }
171
+
172
+ private executeAfterPendingDispatches(): void {
173
+ if (!this.hasOutstandingNonLongPollingRequests()) {
174
+ const scripts = this.#pendingScripts;
175
+ this.#pendingScripts = [];
176
+ for (let id = 0; id < scripts.length; ++id) {
177
+ scripts[id]();
178
+ }
179
+ }
180
+ }
181
+ }
@@ -8,18 +8,16 @@ import type * as Protocol from '../../generated/protocol.js';
8
8
  import type * as Platform from '../platform/platform.js';
9
9
 
10
10
  import {
11
- type CDPCommandRequest,
12
11
  type CDPConnection,
13
12
  type CDPConnectionObserver,
14
- type CDPError,
15
13
  CDPErrorStatus,
16
- type CDPReceivableMessage,
14
+ type CDPEvent,
17
15
  type Command,
18
16
  type CommandParams,
19
- type CommandResult
17
+ type Event
20
18
  } from './CDPConnection.js';
21
19
  import {ConnectionTransport} from './ConnectionTransport.js';
22
- import {NodeURL} from './NodeURL.js';
20
+ import {DevToolsCDPConnection} from './DevToolsCDPConnection.js';
23
21
 
24
22
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
23
  type MessageParams = Record<string, any>;
@@ -66,14 +64,6 @@ type ReadonlyEventParameterNames = ReadonlyMap<QualifiedName, string[]>;
66
64
 
67
65
  type CommandParameter = InspectorBackendCommands.CommandParameter;
68
66
 
69
- type Callback = (error: MessageError|null, arg1: Object|null) => void;
70
-
71
- interface CallbackWithDebugInfo {
72
- resolve: (response: Awaited<ReturnType<CDPConnection['send']>>) => void;
73
- method: string;
74
- sessionId: string|undefined;
75
- }
76
-
77
67
  export class InspectorBackend implements InspectorBackendCommands.InspectorBackendAPI {
78
68
  readonly agentPrototypes = new Map<ProtocolDomainName, AgentPrototype>();
79
69
  #eventParameterNamesForDomain = new Map<ProtocolDomainName, EventParameterNames>();
@@ -192,43 +182,15 @@ export const test = {
192
182
  onMessageReceived: null as ((message: Object) => void) | null,
193
183
  };
194
184
 
195
- const LongPollingMethods = new Set<string>(['CSS.takeComputedStyleUpdates']);
196
-
197
- export class SessionRouter implements CDPConnection {
198
- readonly #connection: ConnectionTransport;
199
- #lastMessageId = 1;
200
- #pendingResponsesCount = 0;
201
- readonly #pendingLongPollingMessageIds = new Set<number>();
185
+ export class SessionRouter implements CDPConnectionObserver {
186
+ readonly #connection: CDPConnection;
202
187
  readonly #sessions = new Map<string, {
203
188
  target: TargetBase,
204
189
  }>();
205
- #pendingScripts: Array<() => void> = [];
206
- readonly #callbacks = new Map<number, CallbackWithDebugInfo>();
207
- readonly #observers = new Set<CDPConnectionObserver>();
208
190
 
209
- constructor(connection: ConnectionTransport) {
191
+ constructor(connection: CDPConnection) {
210
192
  this.#connection = connection;
211
-
212
- test.deprecatedRunAfterPendingDispatches = this.deprecatedRunAfterPendingDispatches.bind(this);
213
- test.sendRawMessage = this.sendRawMessageForTesting.bind(this);
214
-
215
- this.#connection.setOnMessage(this.onMessage.bind(this));
216
-
217
- this.#connection.setOnDisconnect(reason => {
218
- const session = this.#sessions.get('');
219
- if (session) {
220
- session.target.dispose(reason);
221
- }
222
- this.#observers.forEach(observer => observer.onDisconnect(reason));
223
- });
224
- }
225
-
226
- observe(observer: CDPConnectionObserver): void {
227
- this.#observers.add(observer);
228
- }
229
-
230
- unobserve(observer: CDPConnectionObserver): void {
231
- this.#observers.delete(observer);
193
+ this.#connection.observe(this);
232
194
  }
233
195
 
234
196
  registerSession(target: TargetBase, sessionId: string): void {
@@ -240,145 +202,27 @@ export class SessionRouter implements CDPConnection {
240
202
  if (!session) {
241
203
  return;
242
204
  }
243
- for (const {resolve, method, sessionId: callbackSessionId} of this.#callbacks.values()) {
244
- if (sessionId !== callbackSessionId) {
245
- continue;
246
- }
247
- resolve({
248
- error: {
249
- message: `Session is unregistering, can\'t dispatch pending call to ${method}`,
250
- code: CDPErrorStatus.SESSION_NOT_FOUND,
251
- }
252
- });
205
+ if (this.#connection instanceof DevToolsCDPConnection) {
206
+ this.#connection.resolvePendingCalls(sessionId);
253
207
  }
254
208
  this.#sessions.delete(sessionId);
255
209
  }
256
210
 
257
- private nextMessageId(): number {
258
- return this.#lastMessageId++;
259
- }
260
-
261
- connection(): ConnectionTransport {
262
- return this.#connection;
263
- }
264
-
265
- send<T extends Command>(method: T, params: CommandParams<T>, sessionId: string|undefined):
266
- Promise<{result: CommandResult<T>}|{error: CDPError}> {
267
- const messageId = this.nextMessageId();
268
- const messageObject: Partial<CDPCommandRequest<T>> = {
269
- id: messageId,
270
- method,
271
- };
272
-
273
- if (params) {
274
- messageObject.params = params;
275
- }
276
- if (sessionId) {
277
- messageObject.sessionId = sessionId;
278
- }
279
-
280
- if (test.dumpProtocol) {
281
- test.dumpProtocol('frontend: ' + JSON.stringify(messageObject));
282
- }
283
-
284
- if (test.onMessageSent) {
285
- const domain = method.split('.')[0];
286
- const paramsObject = JSON.parse(JSON.stringify(params || {}));
287
- test.onMessageSent({domain, method, params: (paramsObject as Object), id: messageId, sessionId});
211
+ onDisconnect(reason: string): void {
212
+ const session = this.#sessions.get('');
213
+ if (session) {
214
+ session.target.dispose(reason);
288
215
  }
289
-
290
- ++this.#pendingResponsesCount;
291
- if (LongPollingMethods.has(method)) {
292
- this.#pendingLongPollingMessageIds.add(messageId);
293
- }
294
-
295
- return new Promise(resolve => {
296
- this.#callbacks.set(messageId, {resolve, method, sessionId});
297
- this.#connection.sendRawMessage(JSON.stringify(messageObject));
298
- });
299
- }
300
-
301
- private sendRawMessageForTesting(method: QualifiedName, params: Object|null, callback: Callback|null, sessionId = ''):
302
- void {
303
- void this.send(method as Command, params as CommandParams<Command>, sessionId).then(response => {
304
- if ('error' in response && response.error) {
305
- callback?.(response.error, null);
306
- } else if ('result' in response) {
307
- callback?.(null, response.result as Object | null);
308
- }
309
- });
310
216
  }
311
217
 
312
- private onMessage(message: string|Object): void {
313
- if (test.dumpProtocol) {
314
- test.dumpProtocol('backend: ' + ((typeof message === 'string') ? message : JSON.stringify(message)));
315
- }
316
-
317
- if (test.onMessageReceived) {
318
- const messageObjectCopy = JSON.parse((typeof message === 'string') ? message : JSON.stringify(message));
319
- test.onMessageReceived(messageObjectCopy);
320
- }
321
-
322
- const messageObject = ((typeof message === 'string') ? JSON.parse(message) : message) as CDPReceivableMessage;
323
-
324
- const sessionId = messageObject.sessionId || '';
218
+ onEvent<T extends Event>(event: CDPEvent<T>): void {
219
+ const sessionId = event.sessionId || '';
325
220
  const session = this.#sessions.get(sessionId);
326
-
327
- if (session?.target.getNeedsNodeJSPatching()) {
328
- NodeURL.patch(messageObject);
329
- }
330
-
331
- if ('id' in messageObject && messageObject.id !== undefined) { // just a response for some request
332
- const callback = this.#callbacks.get(messageObject.id);
333
- this.#callbacks.delete(messageObject.id);
334
- if (!callback) {
335
- // Ignore messages with unknown IDs, we might see puppeteer proxied messages here.
336
- return;
337
- }
338
-
339
- callback.resolve(messageObject);
340
- --this.#pendingResponsesCount;
341
- this.#pendingLongPollingMessageIds.delete(messageObject.id);
342
-
343
- if (this.#pendingScripts.length && !this.hasOutstandingNonLongPollingRequests()) {
344
- this.deprecatedRunAfterPendingDispatches();
345
- }
346
- } else if ('method' in messageObject) {
347
- // This cast is justified as we just checked for the presence of messageObject.method.
348
- session?.target.dispatch(messageObject as unknown as EventMessage);
349
- this.#observers.forEach(observer => observer.onEvent(messageObject));
350
- } else {
351
- InspectorBackend.reportProtocolError('Protocol Error: the message without method', messageObject);
352
- }
353
- }
354
-
355
- private hasOutstandingNonLongPollingRequests(): boolean {
356
- return this.#pendingResponsesCount - this.#pendingLongPollingMessageIds.size > 0;
221
+ session?.target.dispatch(event as unknown as EventMessage);
357
222
  }
358
223
 
359
- private deprecatedRunAfterPendingDispatches(script?: (() => void)): void {
360
- if (script) {
361
- this.#pendingScripts.push(script);
362
- }
363
-
364
- // Execute all promises.
365
- window.setTimeout(() => {
366
- if (!this.hasOutstandingNonLongPollingRequests()) {
367
- this.executeAfterPendingDispatches();
368
- } else {
369
- this.deprecatedRunAfterPendingDispatches();
370
- }
371
- }, 0);
372
- }
373
-
374
- private executeAfterPendingDispatches(): void {
375
- if (!this.hasOutstandingNonLongPollingRequests()) {
376
- const scripts = this.#pendingScripts;
377
- this.#pendingScripts = [];
378
- for (let id = 0; id < scripts.length; ++id) {
379
- scripts[id]();
380
- }
381
- }
224
+ get connection(): CDPConnection {
225
+ return this.#connection;
382
226
  }
383
227
  }
384
228
 
@@ -401,16 +245,12 @@ interface DispatcherMap extends Map<ProtocolDomainName, ProtocolProxyApi.Protoco
401
245
  }
402
246
 
403
247
  export class TargetBase {
404
- needsNodeJSPatching: boolean;
405
248
  readonly sessionId: string;
406
249
  #router: SessionRouter|null;
407
250
  #agents: AgentsMap = new Map();
408
251
  #dispatchers: DispatcherMap = new Map();
409
252
 
410
- constructor(
411
- needsNodeJSPatching: boolean, parentTarget: TargetBase|null, sessionId: string,
412
- connection: ConnectionTransport|null) {
413
- this.needsNodeJSPatching = needsNodeJSPatching;
253
+ constructor(parentTarget: TargetBase|null, sessionId: string, connection: CDPConnection|null) {
414
254
  this.sessionId = sessionId;
415
255
 
416
256
  if (parentTarget && !sessionId) {
@@ -423,7 +263,7 @@ export class TargetBase {
423
263
  } else if (connection) {
424
264
  router = new SessionRouter(connection);
425
265
  } else {
426
- router = new SessionRouter(ConnectionTransport.getFactory()());
266
+ router = new SessionRouter(new DevToolsCDPConnection(ConnectionTransport.getFactory()()));
427
267
  }
428
268
 
429
269
  this.#router = router;
@@ -465,10 +305,6 @@ export class TargetBase {
465
305
  return !this.#router;
466
306
  }
467
307
 
468
- markAsNodeJSForTest(): void {
469
- this.needsNodeJSPatching = true;
470
- }
471
-
472
308
  router(): SessionRouter|null {
473
309
  return this.#router;
474
310
  }
@@ -798,10 +634,6 @@ export class TargetBase {
798
634
  registerWebAuthnDispatcher(dispatcher: ProtocolProxyApi.WebAuthnDispatcher): void {
799
635
  this.registerDispatcher('WebAuthn', dispatcher);
800
636
  }
801
-
802
- getNeedsNodeJSPatching(): boolean {
803
- return this.needsNodeJSPatching;
804
- }
805
637
  }
806
638
 
807
639
  /** These are not logged as console.error */
@@ -844,25 +676,26 @@ class AgentPrototype {
844
676
  }
845
677
 
846
678
  private invoke(method: QualifiedName, request: Object|null): Promise<Protocol.ProtocolResponseWithError> {
847
- const router = this.target.router();
848
- if (!router) {
679
+ const connection = this.target.router()?.connection;
680
+ if (!connection) {
849
681
  return Promise.resolve(
850
682
  {result: null, getError: () => `Connection is closed, can\'t dispatch pending call to ${method}`});
851
683
  }
852
684
 
853
- return router.send(method as Command, request as CommandParams<Command>, this.target.sessionId).then(response => {
854
- if ('error' in response && response.error) {
855
- if (!test.suppressRequestErrors && !IGNORED_ERRORS.has(response.error.code)) {
856
- console.error('Request ' + method + ' failed. ' + JSON.stringify(response.error));
857
- }
858
- return {getError: () => response.error.message};
859
- }
860
-
861
- if ('result' in response) {
862
- return {...response.result, getError: () => undefined};
863
- }
864
- return {getError: () => undefined};
865
- });
685
+ return connection.send(method as Command, request as CommandParams<Command>, this.target.sessionId)
686
+ .then(response => {
687
+ if ('error' in response && response.error) {
688
+ if (!test.suppressRequestErrors && !IGNORED_ERRORS.has(response.error.code)) {
689
+ console.error('Request ' + method + ' failed. ' + JSON.stringify(response.error));
690
+ }
691
+ return {getError: () => response.error.message};
692
+ }
693
+
694
+ if ('result' in response) {
695
+ return {...response.result, getError: () => undefined};
696
+ }
697
+ return {getError: () => undefined};
698
+ });
866
699
  }
867
700
  }
868
701
 
@@ -4,12 +4,12 @@
4
4
 
5
5
  import * as CDPConnection from './CDPConnection.js';
6
6
  import * as ConnectionTransport from './ConnectionTransport.js';
7
+ import * as DevToolsCDPConnection from './DevToolsCDPConnection.js';
7
8
  import * as InspectorBackend from './InspectorBackend.js';
8
- import * as NodeURL from './NodeURL.js';
9
9
 
10
10
  export {
11
11
  CDPConnection,
12
12
  ConnectionTransport,
13
+ DevToolsCDPConnection,
13
14
  InspectorBackend,
14
- NodeURL,
15
15
  };
@@ -5,9 +5,8 @@
5
5
  import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
6
6
  import * as Protocol from '../../generated/protocol.js';
7
7
  import * as Common from '../common/common.js';
8
- import * as Host from '../host/host.js';
9
8
  import * as i18n from '../i18n/i18n.js';
10
- import * as Platform from '../platform/platform.js';
9
+ import type * as Platform from '../platform/platform.js';
11
10
  import * as Root from '../root/root.js';
12
11
 
13
12
  import type {PageResourceLoadInitiator} from './PageResourceLoader.js';
@@ -18,7 +17,7 @@ import {Script} from './Script.js';
18
17
  import {SDKModel} from './SDKModel.js';
19
18
  import {SourceMap} from './SourceMap.js';
20
19
  import {SourceMapManager} from './SourceMapManager.js';
21
- import {Capability, type Target, Type} from './Target.js';
20
+ import {Capability, type Target} from './Target.js';
22
21
 
23
22
  const UIStrings = {
24
23
  /**
@@ -456,17 +455,6 @@ export class DebuggerModel extends SDKModel<EventTypes> {
456
455
  async setBreakpointByURL(
457
456
  url: Platform.DevToolsPath.UrlString, lineNumber: number, columnNumber?: number,
458
457
  condition?: BackendCondition): Promise<SetBreakpointResult> {
459
- // Convert file url to node-js path.
460
- let urlRegex;
461
- if (this.target().type() === Type.NODE && Common.ParsedURL.schemeIs(url, 'file:')) {
462
- const platformPath = Common.ParsedURL.ParsedURL.urlToRawPathString(url, Host.Platform.isWin());
463
- urlRegex =
464
- `${Platform.StringUtilities.escapeForRegExp(platformPath)}|${Platform.StringUtilities.escapeForRegExp(url)}`;
465
- if (Host.Platform.isWin() && platformPath.match(/^.:\\/)) {
466
- // Match upper or lower case drive letter
467
- urlRegex = `[${platformPath[0].toUpperCase()}${platformPath[0].toLowerCase()}]` + urlRegex.substr(1);
468
- }
469
- }
470
458
  // Adjust column if needed.
471
459
  let minColumnNumber = 0;
472
460
  const scripts = this.#scriptsBySourceURL.get(url) || [];
@@ -479,8 +467,7 @@ export class DebuggerModel extends SDKModel<EventTypes> {
479
467
  columnNumber = Math.max(columnNumber || 0, minColumnNumber);
480
468
  const response = await this.agent.invoke_setBreakpointByUrl({
481
469
  lineNumber,
482
- url: urlRegex ? undefined : url,
483
- urlRegex,
470
+ url,
484
471
  columnNumber,
485
472
  condition,
486
473
  });
@@ -841,6 +841,10 @@ export class LocalJSONObject extends RemoteObject {
841
841
  return 'date';
842
842
  }
843
843
 
844
+ if (this.#value instanceof Error) {
845
+ return 'error';
846
+ }
847
+
844
848
  return undefined;
845
849
  }
846
850
 
@@ -39,10 +39,8 @@ export class Target extends ProtocolClient.InspectorBackend.TargetBase {
39
39
  constructor(
40
40
  targetManager: TargetManager, id: Protocol.Target.TargetID|'main', name: string, type: Type,
41
41
  parentTarget: Target|null, sessionId: string, suspended: boolean,
42
- connection: ProtocolClient.ConnectionTransport.ConnectionTransport|null,
43
- targetInfo?: Protocol.Target.TargetInfo) {
44
- const needsNodeJSPatching = type === Type.NODE;
45
- super(needsNodeJSPatching, parentTarget, sessionId, connection);
42
+ connection: ProtocolClient.CDPConnection.CDPConnection|null, targetInfo?: Protocol.Target.TargetInfo) {
43
+ super(parentTarget, sessionId, connection);
46
44
  this.#targetManager = targetManager;
47
45
  this.#name = name;
48
46
  this.#capabilitiesMask = 0;
@@ -151,8 +149,7 @@ export class Target extends ProtocolClient.InspectorBackend.TargetBase {
151
149
  return this.#type;
152
150
  }
153
151
 
154
- override markAsNodeJSForTest(): void {
155
- super.markAsNodeJSForTest();
152
+ markAsNodeJSForTest(): void {
156
153
  this.#type = Type.NODE;
157
154
  }
158
155