chrome-devtools-frontend 1.0.1539728 → 1.0.1541169

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 (196) hide show
  1. package/eslint.config.mjs +167 -151
  2. package/front_end/core/common/Debouncer.ts +2 -2
  3. package/front_end/core/common/Gzip.ts +1 -1
  4. package/front_end/core/common/Revealer.ts +5 -0
  5. package/front_end/core/common/Throttler.ts +3 -3
  6. package/front_end/core/host/GdpClient.ts +4 -0
  7. package/front_end/core/host/InspectorFrontendHost.ts +10 -10
  8. package/front_end/core/protocol_client/DevToolsCDPConnection.ts +181 -0
  9. package/front_end/core/protocol_client/InspectorBackend.ts +36 -203
  10. package/front_end/core/protocol_client/protocol_client.ts +2 -2
  11. package/front_end/core/sdk/DebuggerModel.ts +3 -16
  12. package/front_end/core/sdk/NetworkManager.ts +16 -11
  13. package/front_end/core/sdk/RemoteObject.ts +4 -0
  14. package/front_end/core/sdk/Target.ts +3 -6
  15. package/front_end/core/sdk/TargetManager.ts +1 -2
  16. package/front_end/core/sdk/sdk-meta.ts +0 -35
  17. package/front_end/entrypoints/lighthouse_worker/LighthouseWorkerService.ts +1 -3
  18. package/front_end/entrypoints/node_app/app/NodeMain.ts +3 -2
  19. package/front_end/entrypoints/shell/shell.ts +1 -0
  20. package/front_end/entrypoints/trace_app/trace_app.ts +1 -0
  21. package/front_end/generated/Deprecation.ts +8 -0
  22. package/front_end/generated/InspectorBackendCommands.ts +8 -5
  23. package/front_end/generated/SupportedCSSProperties.js +58 -4
  24. package/front_end/generated/protocol.ts +60 -4
  25. package/front_end/models/ai_assistance/EvaluateAction.ts +88 -5
  26. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +121 -56
  27. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +104 -62
  28. package/front_end/models/ai_assistance/injected.ts +15 -2
  29. package/front_end/models/ai_assistance/performance/AIQueries.ts +56 -2
  30. package/front_end/{panels/issues → models/issues_manager}/IssueAggregator.ts +83 -65
  31. package/front_end/models/issues_manager/issues_manager.ts +2 -0
  32. package/front_end/models/live-metrics/web-vitals-injected/README.md +1 -1
  33. package/front_end/models/trace/Processor.ts +5 -4
  34. package/front_end/models/trace/Styles.ts +1 -1
  35. package/front_end/models/trace/insights/types.ts +1 -1
  36. package/front_end/models/trace/types/TraceEvents.ts +1 -1
  37. package/front_end/models/workspace/IgnoreListManager.ts +41 -47
  38. package/front_end/models/workspace/workspace-meta.ts +40 -0
  39. package/front_end/panels/ai_assistance/PatchWidget.ts +22 -12
  40. package/front_end/panels/ai_assistance/components/ChatView.ts +1 -1
  41. package/front_end/panels/animation/AnimationTimeline.ts +4 -4
  42. package/front_end/panels/animation/AnimationUI.ts +28 -34
  43. package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +4 -4
  44. package/front_end/panels/common/AiCodeCompletionSummaryToolbar.ts +2 -2
  45. package/front_end/panels/elements/ElementsTreeElement.ts +37 -9
  46. package/front_end/panels/elements/LayoutPane.ts +2 -2
  47. package/front_end/panels/elements/PropertiesWidget.ts +3 -2
  48. package/front_end/panels/elements/components/AdornerManager.ts +9 -9
  49. package/front_end/panels/elements/layoutPane.css +5 -9
  50. package/front_end/panels/event_listeners/EventListenersView.ts +10 -6
  51. package/front_end/panels/explain/components/ConsoleInsight.ts +498 -449
  52. package/front_end/panels/issues/AffectedResourcesView.ts +3 -4
  53. package/front_end/panels/issues/CorsIssueDetailsView.ts +1 -2
  54. package/front_end/panels/issues/IssueView.ts +1 -1
  55. package/front_end/panels/issues/IssuesPane.ts +12 -15
  56. package/front_end/panels/issues/issues.ts +0 -2
  57. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +3 -3
  58. package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +2 -2
  59. package/front_end/panels/network/NetworkDataGridNode.ts +2 -1
  60. package/front_end/panels/network/RequestConditionsDrawer.ts +149 -46
  61. package/front_end/panels/network/RequestPayloadView.ts +2 -1
  62. package/front_end/panels/network/RequestTimingView.ts +17 -10
  63. package/front_end/panels/network/components/RequestHeadersView.ts +24 -17
  64. package/front_end/panels/network/network-meta.ts +11 -0
  65. package/front_end/panels/protocol_monitor/JSONEditor.ts +2 -2
  66. package/front_end/panels/recorder/RecorderController.ts +6 -7
  67. package/front_end/panels/recorder/models/RecordingPlayer.ts +3 -3
  68. package/front_end/panels/settings/components/SyncSection.ts +1 -1
  69. package/front_end/panels/settings/emulation/components/userAgentClientHintsForm.css +1 -1
  70. package/front_end/panels/sources/BreakpointsView.ts +3 -3
  71. package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
  72. package/front_end/panels/sources/ScopeChainSidebarPane.ts +4 -3
  73. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +4 -3
  74. package/front_end/panels/sources/breakpointsView.css +1 -1
  75. package/front_end/panels/sources/sourcesPanel.css +2 -2
  76. package/front_end/panels/timeline/TimelineFlameChartView.ts +3 -3
  77. package/front_end/panels/timeline/TimelinePanel.ts +3 -3
  78. package/front_end/panels/timeline/components/FieldSettingsDialog.ts +9 -5
  79. package/front_end/panels/timeline/components/LayoutShiftDetails.ts +16 -10
  80. package/front_end/panels/timeline/components/LiveMetricsView.ts +20 -9
  81. package/front_end/panels/timeline/components/MetricCard.ts +4 -2
  82. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +2 -0
  83. package/front_end/services/puppeteer/PuppeteerConnection.ts +2 -1
  84. package/front_end/third_party/chromium/README.chromium +1 -1
  85. package/front_end/third_party/puppeteer/README.chromium +2 -2
  86. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +5 -0
  87. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  88. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  89. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts +1 -0
  90. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts.map +1 -1
  91. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js +3 -0
  92. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js.map +1 -1
  93. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts +1 -0
  94. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +21 -0
  96. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/ExtensionTransport.d.ts.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/ExtensionTransport.js +5 -1
  99. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/ExtensionTransport.js.map +1 -1
  100. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts +1 -0
  101. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +6 -0
  103. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.d.ts +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.d.ts.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.js +29 -27
  107. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.js.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  110. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +5 -0
  113. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +61 -26
  114. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +5 -0
  115. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  116. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts +1 -0
  118. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js +3 -0
  120. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts +1 -0
  122. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +21 -0
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/ExtensionTransport.d.ts.map +1 -1
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/ExtensionTransport.js +5 -1
  127. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/ExtensionTransport.js.map +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts +1 -0
  129. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
  130. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +6 -0
  131. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  132. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.d.ts +1 -1
  133. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.d.ts.map +1 -1
  134. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.js +30 -28
  135. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.js.map +1 -1
  136. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
  137. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
  138. package/front_end/third_party/puppeteer/package/lib/types.d.ts +5 -0
  139. package/front_end/third_party/puppeteer/package/package.json +1 -1
  140. package/front_end/third_party/puppeteer/package/src/api/Page.ts +6 -0
  141. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +4 -0
  142. package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +32 -0
  143. package/front_end/third_party/puppeteer/package/src/cdp/ExtensionTransport.ts +5 -1
  144. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +8 -0
  145. package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +36 -43
  146. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  147. package/front_end/ui/components/dialogs/ButtonDialog.ts +15 -5
  148. package/front_end/ui/components/expandable_list/ExpandableList.ts +1 -1
  149. package/front_end/ui/components/helpers/helpers.ts +0 -2
  150. package/front_end/ui/components/markdown_view/MarkdownView.ts +1 -0
  151. package/front_end/ui/components/menus/Menu.ts +5 -3
  152. package/front_end/ui/components/snackbars/Snackbars.docs.ts +46 -0
  153. package/front_end/ui/components/survey_link/SurveyLink.docs.ts +22 -0
  154. package/front_end/ui/components/tree_outline/TreeOutline.ts +1 -2
  155. package/front_end/ui/{components/docs/context_menu/basic.ts → legacy/ContextMenu.docs.ts} +58 -25
  156. package/front_end/ui/legacy/SelectMenu.docs.ts +14 -0
  157. package/front_end/ui/legacy/UIUtils.ts +2 -1
  158. package/front_end/ui/legacy/components/inline_editor/BezierEditor.ts +1 -1
  159. package/front_end/ui/legacy/components/object_ui/CustomPreviewComponent.ts +3 -1
  160. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +558 -439
  161. package/front_end/ui/legacy/components/perf_ui/TimelineOverviewPane.ts +3 -3
  162. package/front_end/ui/legacy/components/perf_ui/pieChart.css +1 -1
  163. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
  164. package/front_end/ui/legacy/inspectorCommon.css +3 -2
  165. package/mcp/mcp.ts +15 -1
  166. package/package.json +2 -1
  167. package/front_end/core/protocol_client/NodeURL.ts +0 -40
  168. package/front_end/ui/components/docs/combo_box/basic.html +0 -20
  169. package/front_end/ui/components/docs/combo_box/basic.ts +0 -49
  170. package/front_end/ui/components/docs/context_menu/basic.html +0 -45
  171. package/front_end/ui/components/docs/legacy_color_invert/basic.html +0 -77
  172. package/front_end/ui/components/docs/legacy_color_invert/basic.ts +0 -98
  173. package/front_end/ui/components/docs/linkifier/simple-url.html +0 -25
  174. package/front_end/ui/components/docs/linkifier/simple-url.ts +0 -25
  175. package/front_end/ui/components/docs/panel_feedback/basic.html +0 -25
  176. package/front_end/ui/components/docs/panel_feedback/basic.ts +0 -21
  177. package/front_end/ui/components/docs/panel_feedback/button.html +0 -25
  178. package/front_end/ui/components/docs/panel_feedback/button.ts +0 -19
  179. package/front_end/ui/components/docs/panel_introduction_steps/basic.html +0 -25
  180. package/front_end/ui/components/docs/panel_introduction_steps/basic.ts +0 -28
  181. package/front_end/ui/components/docs/perf_piechart/basic-with-legend.html +0 -20
  182. package/front_end/ui/components/docs/perf_piechart/basic-with-legend.ts +0 -20
  183. package/front_end/ui/components/docs/perf_piechart/basic-without-legend.html +0 -20
  184. package/front_end/ui/components/docs/perf_piechart/basic-without-legend.ts +0 -18
  185. package/front_end/ui/components/docs/snackbars/basic.html +0 -17
  186. package/front_end/ui/components/docs/snackbars/basic.ts +0 -50
  187. package/front_end/ui/components/docs/survey_link/basic.html +0 -20
  188. package/front_end/ui/components/docs/survey_link/basic.ts +0 -28
  189. package/front_end/ui/components/docs/tree_outline/basic.html +0 -33
  190. package/front_end/ui/components/docs/tree_outline/basic.ts +0 -38
  191. package/front_end/ui/components/docs/tree_outline/custom-renderers.html +0 -32
  192. package/front_end/ui/components/docs/tree_outline/custom-renderers.ts +0 -61
  193. package/front_end/ui/components/docs/tree_outline/lazy-children.html +0 -32
  194. package/front_end/ui/components/docs/tree_outline/lazy-children.ts +0 -91
  195. package/front_end/ui/components/docs/tree_outline/sample-data.ts +0 -67
  196. 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
  });
@@ -26,6 +26,10 @@ const UIStrings = {
26
26
  * @description The UI destination when right clicking an item that can be revealed
27
27
  */
28
28
  networkPanel: 'Network panel',
29
+ /**
30
+ * @description The UI destination when right clicking an item that can be revealed
31
+ */
32
+ requestConditionsDrawer: 'Request conditions drawer',
29
33
  /**
30
34
  * @description The UI destination when right clicking an item that can be revealed
31
35
  */
@@ -181,6 +185,7 @@ export const RevealerDestination = {
181
185
  CHANGES_DRAWER: i18nLazyString(UIStrings.changesDrawer),
182
186
  ISSUES_VIEW: i18nLazyString(UIStrings.issuesView),
183
187
  NETWORK_PANEL: i18nLazyString(UIStrings.networkPanel),
188
+ REQUEST_CONDITIONS_DRAWER: i18nLazyString(UIStrings.requestConditionsDrawer),
184
189
  TIMELINE_PANEL: i18nLazyString(UIStrings.timelinePanel),
185
190
  APPLICATION_PANEL: i18nLazyString(UIStrings.applicationPanel),
186
191
  SOURCES_PANEL: i18nLazyString(UIStrings.sourcesPanel),
@@ -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();
@@ -491,19 +491,19 @@ export class InspectorFrontendHostStub implements InspectorFrontendHostAPI {
491
491
  * Whereas in **Non-hosted** (aka "embedded"), DevTools is embedded and fully dockable. It's the common way DevTools is run.
492
492
  *
493
493
  * **Hosted mode** == we're using the `InspectorFrontendHostStub`. impl. (@see `InspectorFrontendHostStub` class comment)
494
- * Whereas with **non-hosted** mode, native `DevToolsEmbedderMessageDispatcher` is used for CDP and more.
494
+ * Whereas with **non-hosted** mode, native `DevToolsEmbedderMessageDispatcher` is used for CDP and more. `globalThis.DevToolsAPI` is present.
495
495
  *
496
496
  * Relationships to other signals:
497
- * - Hosted-ness does not indicate whether the frontend is _connected to a valid CDP target_.
498
- * - Being _"dockable"_ (aka `canDock`) is typically aligned but technically orthogonal.
499
- * - It's unrelated to the _tab's (main frame's) URL_. Though in non-hosted, the devtools frame origin will always be `devtools://devtools`.
497
+ * - _Connection_: Hosted-ness does not indicate whether the frontend is _connected to a valid CDP target_.
498
+ * - _Dockability_: Being _"dockable"_ (aka `canDock`) is typically aligned but technically orthogonal.
499
+ * - _URL scheme_: If the main frame's URL scheme is `devtools://`, it's non-hosted.
500
500
  *
501
- * | Example case | Mode | Example devtools |
502
- * | :--------------------------------------------------- | :------------- | :---------------------------------------------------------------------------- |
503
- * | tab URL: anything. embedded DevTools w/ native CDP bindings | **NOT Hosted** | `devtools://devtools/bundled/devtools_app.html?targetType=tab&...` |
504
- * | tab URL: `devtools://…?ws=…` | **Hosted** | `devtools://devtools/bundled/devtools_app.html?ws=localhost:9228/...` |
505
- * | tab URL: `devtools://…` but no connection | **Hosted** | `devtools://devtools/bundled/devtools_app.html` |
506
- * | tab URL: `https://…` but no connection | **Hosted** | `https://chrome-devtools-frontend.appspot.com/serve_rev/@.../worker_app.html` |
501
+ * | Example case | Mode | Example devtools |
502
+ * | :------------------------------------------ | :------------- | :---------------------------------------------------------------------------- |
503
+ * | tab URL: `devtools://…` | **NOT Hosted** | `devtools://devtools/bundled/devtools_app.html?targetType=tab&...` |
504
+ * | tab URL: `devtools://…?ws=…` | **NOT Hosted** | `devtools://devtools/bundled/devtools_app.html?ws=localhost:9228/...` |
505
+ * | tab URL: `devtools://…` but no connection | **NOT Hosted** | `devtools://devtools/bundled/trace_app.html` |
506
+ * | tab URL: `https://…` but no connection | **Hosted** | `https://chrome-devtools-frontend.appspot.com/serve_rev/@.../trace_app.html` |
507
507
  * | tab URL: `http://…?ws=` (connected) | **Hosted** | `http://localhost:9222/devtools/inspector.html?ws=localhost:9222/...` |
508
508
  */
509
509
  isHostedMode(): boolean {
@@ -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
  };