chrome-devtools-frontend 1.0.1514545 → 1.0.1515796

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 (163) hide show
  1. package/AUTHORS +1 -0
  2. package/docs/committers_policy.md +1 -1
  3. package/docs/contributing/infrastructure.md +101 -5
  4. package/front_end/Images/gdp-logo-dark.png +0 -0
  5. package/front_end/Images/gdp-logo-light.png +0 -0
  6. package/front_end/core/common/Settings.ts +11 -32
  7. package/front_end/entrypoints/main/main-meta.ts +2 -2
  8. package/front_end/generated/InspectorBackendCommands.js +4 -4
  9. package/front_end/generated/SupportedCSSProperties.js +12 -0
  10. package/front_end/generated/protocol.ts +10 -1
  11. package/front_end/global_typings/global_defs.d.ts +15 -1
  12. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +22 -23
  13. package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +6 -7
  14. package/front_end/models/ai_assistance/ai_assistance.ts +3 -0
  15. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +141 -2
  16. package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +96 -10
  17. package/front_end/models/ai_code_completion/AiCodeCompletion.ts +123 -55
  18. package/front_end/models/cpu_profile/ProfileTreeModel.ts +1 -1
  19. package/front_end/models/extensions/ExtensionPanel.ts +4 -0
  20. package/front_end/models/heap_snapshot_model/HeapSnapshotModel.ts +5 -1
  21. package/front_end/models/javascript_metadata/NativeFunctions.js +7 -7
  22. package/front_end/models/text_utils/TextUtils.ts +26 -0
  23. package/front_end/models/trace/Processor.ts +1 -1
  24. package/front_end/models/trace/helpers/Trace.ts +1 -1
  25. package/front_end/models/trace/insights/DocumentLatency.ts +9 -7
  26. package/front_end/models/trace/types/Configuration.ts +12 -0
  27. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +6 -7
  28. package/front_end/panels/ai_assistance/components/ChatView.ts +1 -2
  29. package/front_end/panels/application/components/BackForwardCacheStrings.ts +8 -2
  30. package/front_end/panels/common/BadgeNotification.ts +10 -8
  31. package/front_end/panels/common/GdpSignUpDialog.ts +25 -16
  32. package/front_end/panels/common/gdpSignUpDialog.css +10 -14
  33. package/front_end/panels/console/ConsoleView.ts +4 -0
  34. package/front_end/panels/elements/ElementsPanel.ts +4 -0
  35. package/front_end/panels/elements/StylePropertiesSection.ts +4 -4
  36. package/front_end/panels/network/NetworkConfigView.ts +1 -1
  37. package/front_end/panels/network/NetworkLogView.ts +2 -2
  38. package/front_end/panels/network/components/HeaderSectionRow.ts +2 -3
  39. package/front_end/panels/profiler/HeapProfileView.ts +1 -3
  40. package/front_end/panels/profiler/HeapSnapshotView.ts +5 -1
  41. package/front_end/panels/profiler/ProfileDataGrid.ts +4 -0
  42. package/front_end/panels/profiler/ProfileFlameChartDataProvider.ts +7 -29
  43. package/front_end/panels/profiler/ProfileView.ts +4 -0
  44. package/front_end/panels/recorder/components/CreateRecordingView.ts +2 -2
  45. package/front_end/panels/search/SearchView.ts +322 -248
  46. package/front_end/panels/settings/KeybindsSettingsTab.ts +1 -1
  47. package/front_end/panels/settings/SettingsScreen.ts +1 -1
  48. package/front_end/panels/settings/components/SyncSection.ts +59 -14
  49. package/front_end/panels/settings/components/syncSection.css +17 -4
  50. package/front_end/panels/sources/AiCodeCompletionPlugin.ts +4 -7
  51. package/front_end/panels/sources/SourcesView.ts +4 -0
  52. package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +2 -2
  53. package/front_end/panels/timeline/CompatibilityTracksAppender.ts +6 -3
  54. package/front_end/panels/timeline/CountersGraph.ts +5 -5
  55. package/front_end/panels/timeline/TimelineDetailsView.ts +2 -2
  56. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +4 -3
  57. package/front_end/panels/timeline/TimelineFlameChartView.ts +9 -4
  58. package/front_end/panels/timeline/TimelineHistoryManager.ts +2 -2
  59. package/front_end/panels/timeline/TimelinePanel.ts +4 -3
  60. package/front_end/panels/timeline/TimelineTreeView.ts +6 -2
  61. package/front_end/panels/timeline/TimelineUIUtils.ts +2 -1
  62. package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +2 -2
  63. package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +6 -6
  64. package/front_end/panels/timeline/overlays/OverlaysImpl.ts +2 -2
  65. package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +2 -3
  66. package/front_end/panels/timeline/utils/utils.ts +0 -8
  67. package/front_end/panels/webauthn/WebauthnPane.ts +1 -1
  68. package/front_end/{panels/timeline/utils → services/tracing}/FreshRecording.ts +1 -1
  69. package/front_end/services/tracing/tracing.ts +2 -0
  70. package/front_end/third_party/chromium/README.chromium +1 -1
  71. package/front_end/third_party/puppeteer/README.chromium +2 -2
  72. package/front_end/third_party/puppeteer/package/README.md +6 -3
  73. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +11 -1
  75. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
  76. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js +2 -2
  77. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts +5 -1
  79. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js +30 -8
  81. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js.map +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  83. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js +1 -3
  84. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  85. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
  86. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.d.ts +1 -1
  87. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  88. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js +8 -2
  89. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/NetworkManager.js.map +1 -1
  90. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts +5 -1
  91. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
  92. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +8 -2
  93. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
  94. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
  96. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js +5 -0
  99. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js.map +1 -1
  100. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
  101. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +12 -2
  102. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +22 -8
  103. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +11 -1
  105. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js +2 -2
  107. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts +5 -1
  109. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts.map +1 -1
  110. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js +30 -8
  111. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js.map +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
  113. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js +1 -3
  114. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
  115. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.d.ts +1 -1
  116. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.d.ts.map +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js +8 -2
  118. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/NetworkManager.js.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts +5 -1
  120. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +8 -2
  122. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js +5 -0
  127. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js.map +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/types.d.ts +12 -2
  129. package/front_end/third_party/puppeteer/package/package.json +4 -4
  130. package/front_end/third_party/puppeteer/package/src/api/Browser.ts +1 -1
  131. package/front_end/third_party/puppeteer/package/src/api/Page.ts +13 -2
  132. package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +50 -8
  133. package/front_end/third_party/puppeteer/package/src/bidi/core/BrowsingContext.ts +0 -1
  134. package/front_end/third_party/puppeteer/package/src/cdp/NetworkManager.ts +8 -1
  135. package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +21 -5
  136. package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
  137. package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +12 -0
  138. package/front_end/ui/components/text_editor/config.ts +66 -16
  139. package/front_end/ui/legacy/Dialog.ts +38 -13
  140. package/front_end/ui/legacy/InspectorView.ts +7 -9
  141. package/front_end/ui/legacy/ProgressIndicator.ts +4 -5
  142. package/front_end/ui/legacy/SearchableView.ts +73 -55
  143. package/front_end/ui/legacy/SettingsUI.ts +5 -5
  144. package/front_end/ui/legacy/components/color_picker/Spectrum.ts +1 -4
  145. package/front_end/ui/legacy/components/data_grid/DataGrid.ts +5 -5
  146. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +4 -2
  147. package/front_end/ui/legacy/components/perf_ui/ChartViewport.ts +2 -2
  148. package/front_end/ui/legacy/components/perf_ui/FilmStripView.ts +2 -2
  149. package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +1 -4
  150. package/front_end/ui/legacy/components/perf_ui/OverviewGrid.ts +3 -3
  151. package/front_end/ui/legacy/components/perf_ui/TimelineOverviewPane.ts +2 -2
  152. package/front_end/ui/legacy/components/source_frame/JSONView.ts +10 -10
  153. package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +4 -0
  154. package/front_end/ui/legacy/components/source_frame/XMLView.ts +4 -0
  155. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -4
  156. package/front_end/ui/legacy/searchableView.css +0 -4
  157. package/front_end/ui/visual_logging/Debugging.ts +24 -12
  158. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  159. package/package.json +3 -3
  160. package/front_end/Images/src/gdp-logo-standalone.svg +0 -9
  161. /package/front_end/{panels/timeline/utils → models/ai_assistance/performance}/AICallTree.ts +0 -0
  162. /package/front_end/{panels/timeline/utils → models/ai_assistance/performance}/AIContext.ts +0 -0
  163. /package/front_end/{panels/timeline/utils/InsightAIContext.ts → models/ai_assistance/performance/AIQueries.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "puppeteer-core",
3
- "version": "24.20.0",
3
+ "version": "24.21.0",
4
4
  "description": "A high-level API to control headless Chrome over the DevTools Protocol",
5
5
  "keywords": [
6
6
  "puppeteer",
@@ -140,12 +140,12 @@
140
140
  "author": "The Chromium Authors",
141
141
  "license": "Apache-2.0",
142
142
  "dependencies": {
143
- "@puppeteer/browsers": "2.10.9",
143
+ "@puppeteer/browsers": "2.10.10",
144
144
  "chromium-bidi": "8.0.0",
145
- "debug": "^4.4.1",
145
+ "debug": "^4.4.3",
146
146
  "devtools-protocol": "0.0.1495869",
147
147
  "typed-query-selector": "^2.12.0",
148
- "webdriver-bidi-protocol": "0.2.8",
148
+ "webdriver-bidi-protocol": "0.2.11",
149
149
  "ws": "^8.18.3"
150
150
  },
151
151
  "devDependencies": {
@@ -412,7 +412,7 @@ export abstract class Browser extends EventEmitter<BrowserEvents> {
412
412
  * Gets this {@link Browser | browser's} original user agent.
413
413
  *
414
414
  * {@link Page | Pages} can override the user agent with
415
- * {@link Page.setUserAgent}.
415
+ * {@link Page.(setUserAgent:2) }.
416
416
  *
417
417
  */
418
418
  abstract userAgent(): Promise<string>;
@@ -1655,12 +1655,23 @@ export abstract class Page extends EventEmitter<PageEvents> {
1655
1655
  * @param userAgentData - Specific user agent client hint data to use in this
1656
1656
  * page
1657
1657
  * @returns Promise which resolves when the user agent is set.
1658
+ * @deprecated Use {@link Page.(setUserAgent:2) } instead.
1658
1659
  */
1659
1660
  abstract setUserAgent(
1660
1661
  userAgent: string,
1661
1662
  userAgentMetadata?: Protocol.Emulation.UserAgentMetadata,
1662
1663
  ): Promise<void>;
1663
1664
 
1665
+ /**
1666
+ * @param options - Object containing user agent and optional user agent metadata
1667
+ * @returns Promise which resolves when the user agent is set.
1668
+ */
1669
+ abstract setUserAgent(options: {
1670
+ userAgent?: string;
1671
+ userAgentMetadata?: Protocol.Emulation.UserAgentMetadata;
1672
+ platform?: string;
1673
+ }): Promise<void>;
1674
+
1664
1675
  /**
1665
1676
  * Object containing metrics as key/value pairs.
1666
1677
  *
@@ -2014,7 +2025,7 @@ export abstract class Page extends EventEmitter<PageEvents> {
2014
2025
  *
2015
2026
  * @remarks
2016
2027
  * This method is a shortcut for calling two methods:
2017
- * {@link Page.setUserAgent} and {@link Page.setViewport}.
2028
+ * {@link Page.(setUserAgent:2) } and {@link Page.setViewport}.
2018
2029
  *
2019
2030
  * This method will resize the page. A lot of websites don't expect phones to
2020
2031
  * change size, so you should emulate before navigating to the page.
@@ -2037,7 +2048,7 @@ export abstract class Page extends EventEmitter<PageEvents> {
2037
2048
  */
2038
2049
  async emulate(device: Device): Promise<void> {
2039
2050
  await Promise.all([
2040
- this.setUserAgent(device.userAgent),
2051
+ this.setUserAgent({userAgent: device.userAgent}),
2041
2052
  this.setViewport(device.viewport),
2042
2053
  ]);
2043
2054
  }
@@ -141,20 +141,45 @@ export class BidiPage extends Page {
141
141
  #userAgentInterception?: string;
142
142
  #userAgentPreloadScript?: string;
143
143
  override async setUserAgent(
144
- userAgent: string,
144
+ userAgentOrOptions:
145
+ | string
146
+ | {
147
+ userAgent?: string;
148
+ userAgentMetadata?: Protocol.Emulation.UserAgentMetadata;
149
+ platform?: string;
150
+ },
145
151
  userAgentMetadata?: Protocol.Emulation.UserAgentMetadata,
146
152
  ): Promise<void> {
147
- if (!this.#browserContext.browser().cdpSupported && userAgentMetadata) {
153
+ let userAgent: string;
154
+ let metadata: Protocol.Emulation.UserAgentMetadata | undefined;
155
+ let platform: string | undefined;
156
+
157
+ if (typeof userAgentOrOptions === 'string') {
158
+ userAgent = userAgentOrOptions;
159
+ metadata = userAgentMetadata;
160
+ } else {
161
+ userAgent =
162
+ userAgentOrOptions.userAgent ??
163
+ (await this.#browserContext.browser().userAgent());
164
+ metadata = userAgentOrOptions.userAgentMetadata;
165
+ platform = userAgentOrOptions.platform;
166
+ }
167
+
168
+ if (
169
+ !this.#browserContext.browser().cdpSupported &&
170
+ (metadata || platform)
171
+ ) {
148
172
  throw new UnsupportedOperation(
149
- 'Current Browser does not support `userAgentMetadata`',
173
+ 'Current Browser does not support `userAgentMetadata` or `platform`',
150
174
  );
151
175
  } else if (
152
176
  this.#browserContext.browser().cdpSupported &&
153
- userAgentMetadata
177
+ (metadata || platform)
154
178
  ) {
155
179
  return await this._client().send('Network.setUserAgentOverride', {
156
180
  userAgent: userAgent,
157
- userAgentMetadata: userAgentMetadata,
181
+ userAgentMetadata: metadata,
182
+ platform: platform,
158
183
  });
159
184
  }
160
185
  const enable = userAgent !== '';
@@ -172,11 +197,20 @@ export class BidiPage extends Page {
172
197
  enable,
173
198
  );
174
199
 
175
- const changeUserAgent = (userAgent: string) => {
200
+ const overrideNavigatorProperties = (
201
+ userAgent: string,
202
+ platform: string | undefined,
203
+ ) => {
176
204
  Object.defineProperty(navigator, 'userAgent', {
177
205
  value: userAgent,
178
206
  configurable: true,
179
207
  });
208
+ if (platform) {
209
+ Object.defineProperty(navigator, 'platform', {
210
+ value: platform,
211
+ configurable: true,
212
+ });
213
+ }
180
214
  };
181
215
 
182
216
  const frames = [this.#frame];
@@ -191,12 +225,20 @@ export class BidiPage extends Page {
191
225
  }
192
226
  const [evaluateToken] = await Promise.all([
193
227
  enable
194
- ? this.evaluateOnNewDocument(changeUserAgent, userAgent)
228
+ ? this.evaluateOnNewDocument(
229
+ overrideNavigatorProperties,
230
+ userAgent,
231
+ platform || undefined,
232
+ )
195
233
  : undefined,
196
234
  // When we disable the UserAgent we want to
197
235
  // evaluate the original value in all Browsing Contexts
198
236
  ...frames.map(frame => {
199
- return frame.evaluate(changeUserAgent, userAgent);
237
+ return frame.evaluate(
238
+ overrideNavigatorProperties,
239
+ userAgent,
240
+ platform || undefined,
241
+ );
200
242
  }),
201
243
  ]);
202
244
  this.#userAgentPreloadScript = evaluateToken?.identifier;
@@ -713,7 +713,6 @@ export class BrowsingContext extends EventEmitter<{
713
713
 
714
714
  async setJavaScriptEnabled(enabled: boolean): Promise<void> {
715
715
  await this.userContext.browser.session.send(
716
- // @ts-expect-error missing types
717
716
  'emulation.setScriptingEnabled',
718
717
  {
719
718
  // Enabled `null` means `default`, `false` means `disabled`.
@@ -77,11 +77,12 @@ export class NetworkManager extends EventEmitter<NetworkManagerEvents> {
77
77
  #credentials: Credentials | null = null;
78
78
  #attemptedAuthentications = new Set<string>();
79
79
  #userRequestInterceptionEnabled = false;
80
- #protocolRequestInterceptionEnabled = false;
80
+ #protocolRequestInterceptionEnabled?: boolean;
81
81
  #userCacheDisabled?: boolean;
82
82
  #emulatedNetworkConditions?: InternalNetworkConditions;
83
83
  #userAgent?: string;
84
84
  #userAgentMetadata?: Protocol.Emulation.UserAgentMetadata;
85
+ #platform?: string;
85
86
 
86
87
  readonly #handlers = [
87
88
  ['Fetch.requestPaused', this.#onRequestPaused],
@@ -265,9 +266,11 @@ export class NetworkManager extends EventEmitter<NetworkManagerEvents> {
265
266
  async setUserAgent(
266
267
  userAgent: string,
267
268
  userAgentMetadata?: Protocol.Emulation.UserAgentMetadata,
269
+ platform?: string,
268
270
  ): Promise<void> {
269
271
  this.#userAgent = userAgent;
270
272
  this.#userAgentMetadata = userAgentMetadata;
273
+ this.#platform = platform;
271
274
  await this.#applyToAllClients(this.#applyUserAgent.bind(this));
272
275
  }
273
276
 
@@ -279,6 +282,7 @@ export class NetworkManager extends EventEmitter<NetworkManagerEvents> {
279
282
  await client.send('Network.setUserAgentOverride', {
280
283
  userAgent: this.#userAgent,
281
284
  userAgentMetadata: this.#userAgentMetadata,
285
+ platform: this.#platform,
282
286
  });
283
287
  } catch (error) {
284
288
  if (this.#canIgnoreError(error)) {
@@ -306,6 +310,9 @@ export class NetworkManager extends EventEmitter<NetworkManagerEvents> {
306
310
  }
307
311
 
308
312
  async #applyProtocolRequestInterception(client: CDPSession): Promise<void> {
313
+ if (this.#protocolRequestInterceptionEnabled === undefined) {
314
+ return;
315
+ }
309
316
  if (this.#userCacheDisabled === undefined) {
310
317
  this.#userCacheDisabled = false;
311
318
  }
@@ -747,13 +747,29 @@ export class CdpPage extends Page {
747
747
  }
748
748
 
749
749
  override async setUserAgent(
750
- userAgent: string,
750
+ userAgentOrOptions:
751
+ | string
752
+ | {
753
+ userAgent?: string;
754
+ userAgentMetadata?: Protocol.Emulation.UserAgentMetadata;
755
+ platform?: string;
756
+ },
751
757
  userAgentMetadata?: Protocol.Emulation.UserAgentMetadata,
752
758
  ): Promise<void> {
753
- return await this.#frameManager.networkManager.setUserAgent(
754
- userAgent,
755
- userAgentMetadata,
756
- );
759
+ if (typeof userAgentOrOptions === 'string') {
760
+ return await this.#frameManager.networkManager.setUserAgent(
761
+ userAgentOrOptions,
762
+ userAgentMetadata,
763
+ );
764
+ } else {
765
+ const userAgent =
766
+ userAgentOrOptions.userAgent ?? (await this.browser().userAgent());
767
+ return await this.#frameManager.networkManager.setUserAgent(
768
+ userAgent,
769
+ userAgentOrOptions.userAgentMetadata,
770
+ userAgentOrOptions.platform,
771
+ );
772
+ }
757
773
  }
758
774
 
759
775
  override async metrics(): Promise<Metrics> {
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * @internal
3
3
  */
4
- export const packageVersion = '24.20.0';
4
+ export const packageVersion = '24.21.0';
@@ -181,6 +181,7 @@ export abstract class BrowserLauncher {
181
181
  slowMo,
182
182
  });
183
183
  }
184
+
184
185
  if (protocol === 'webDriverBiDi') {
185
186
  browser = await this.createBiDiOverCdpBrowser(
186
187
  browserProcess,
@@ -210,6 +211,17 @@ export abstract class BrowserLauncher {
210
211
  }
211
212
  } catch (error) {
212
213
  void browserCloseCallback();
214
+ if (
215
+ browserProcess.getRecentLogs().some(line => {
216
+ return line.includes(
217
+ 'Failed to create a ProcessSingleton for your profile directory',
218
+ );
219
+ })
220
+ ) {
221
+ throw new Error(
222
+ `The browser is already running for ${launchArgs.userDataDir}. Use a different \`userDataDir\` or stop the running browser first.`,
223
+ );
224
+ }
213
225
  if (error instanceof BrowsersTimeoutError) {
214
226
  throw new TimeoutError(error.message);
215
227
  }
@@ -132,7 +132,6 @@ function moveCompletionSelectionIfNotConservative(
132
132
  if (CM.completionStatus(view.state) !== 'active') {
133
133
  return false;
134
134
  }
135
- view.dispatch({effects: setAiAutoCompleteSuggestion.of(null)});
136
135
  if (view.state.field(conservativeCompletion, false)) {
137
136
  view.dispatch({effects: disableConservativeCompletion.of(null)});
138
137
  announceSelectedCompletionInfo(view);
@@ -149,7 +148,6 @@ function moveCompletionSelectionBackwardWrapper(): ((view: CM.EditorView) => boo
149
148
  if (CM.completionStatus(view.state) !== 'active') {
150
149
  return false;
151
150
  }
152
- view.dispatch({effects: setAiAutoCompleteSuggestion.of(null)});
153
151
  CM.moveCompletionSelection(false)(view);
154
152
  announceSelectedCompletionInfo(view);
155
153
  return true;
@@ -523,11 +521,11 @@ export const aiAutoCompleteSuggestionState = CM.StateField.define<ActiveSuggesti
523
521
  const {head} = tr.state.selection.main;
524
522
 
525
523
  // If a change happened before the position from which suggestion was generated, set to null.
526
- if (tr.changes.touchesRange(0, from - 1) || head < from) {
524
+ if (head < from) {
527
525
  return null;
528
526
  }
529
527
 
530
- // Check if what's typed is a prefix of the suggestion.
528
+ // Check if what's typed after the AI suggestion is a prefix of the AI suggestion.
531
529
  const typedText = tr.state.doc.sliceString(from, head);
532
530
  return value.text.startsWith(typedText) ? value : null;
533
531
  },
@@ -539,6 +537,11 @@ export function hasActiveAiSuggestion(state: CM.EditorState): boolean {
539
537
 
540
538
  export function acceptAiAutoCompleteSuggestion(view: CM.EditorView):
541
539
  {accepted: boolean, suggestion?: ActiveSuggestion} {
540
+ const selectedCompletion = CM.selectedCompletion(view.state);
541
+ if (selectedCompletion) {
542
+ return {accepted: false};
543
+ }
544
+
542
545
  const suggestion = view.state.field(aiAutoCompleteSuggestionState);
543
546
  if (!suggestion) {
544
547
  return {accepted: false};
@@ -568,23 +571,70 @@ export const aiAutoCompleteSuggestion: CM.Extension = [
568
571
  decorations: CM.DecorationSet = CM.Decoration.none;
569
572
 
570
573
  update(update: CM.ViewUpdate): void {
574
+ // Hide decorations if there is no active AI suggestion.
571
575
  const activeSuggestion = update.state.field(aiAutoCompleteSuggestionState);
572
- const {head, empty} = update.state.selection.main;
573
- let hint = '';
574
- if (activeSuggestion && empty && head >= activeSuggestion.from) {
575
- const {text, from} = activeSuggestion;
576
- const typedText = update.state.doc.sliceString(from, head);
577
- if (text.startsWith(typedText)) {
578
- hint = text.slice(typedText.length);
579
- }
576
+ if (!activeSuggestion) {
577
+ this.decorations = CM.Decoration.none;
578
+ return;
580
579
  }
581
580
 
582
- if (!hint) {
581
+ // Hide AI suggestion while the user is interacting with the traditional
582
+ // autocomplete menu to avoid conflicting suggestions.
583
+ if (CM.completionStatus(update.view.state) === 'pending') {
583
584
  this.decorations = CM.Decoration.none;
584
- } else {
585
- this.decorations =
586
- CM.Decoration.set([CM.Decoration.widget({widget: new CompletionHint(hint), side: 1}).range(head)]);
585
+ return;
587
586
  }
587
+
588
+ // Hide AI suggestion if the user has selected an item from the
589
+ // traditional autocomplete menu that is not the first one.
590
+ const selectedCompletionIndex = CM.selectedCompletionIndex(update.state);
591
+ if (selectedCompletionIndex && selectedCompletionIndex > 0) {
592
+ this.decorations = CM.Decoration.none;
593
+ return;
594
+ }
595
+
596
+ const {head} = update.state.selection.main;
597
+ const selectedCompletion = CM.selectedCompletion(update.state);
598
+ const additionallyTypedText = update.state.doc.sliceString(activeSuggestion.from, head);
599
+ // The user might have typed text after the suggestion is triggered.
600
+ // If the suggestion no longer starts with the typed text, hide it.
601
+ if (!activeSuggestion.text.startsWith(additionallyTypedText)) {
602
+ this.decorations = CM.Decoration.none;
603
+ return;
604
+ }
605
+
606
+ let ghostText = activeSuggestion.text.slice(additionallyTypedText.length);
607
+ if (selectedCompletion) {
608
+ // If the user typed the full selected completion, then we don't check for overlap.
609
+ // (e.g. the user wrote `flex`, traditional suggestion is `flex` and the AI autocompletion is
610
+ // `;\njustify-content: center`. Then, we want to show the AI completion)
611
+ const endsWithCompleteSelectedCompletion =
612
+ update.state.doc.sliceString(head - selectedCompletion.label.length, head) === selectedCompletion.label;
613
+ // If a traditional autocomplete menu is shown, the AI suggestion is only
614
+ // shown if it builds upon the currently selected item. If there is no
615
+ // overlap, we hide the AI suggestion. For example, for the text `console`
616
+ // if the traditional autocomplete suggests `log` and the AI
617
+ // suggests `warn`, there is no overlap and the AI suggestion is hidden.
618
+ if (!endsWithCompleteSelectedCompletion &&
619
+ !TextUtils.TextUtils.getOverlap(selectedCompletion.label, ghostText)) {
620
+ this.decorations = CM.Decoration.none;
621
+ return;
622
+ }
623
+ }
624
+
625
+ // When `conservativeCompletion` is disabled in Console, the editor shows a ghost
626
+ // text for the first item in the traditional autocomplete menu and this ghost text
627
+ // is reflected in `currentHint`. In this case, we need to remove
628
+ // the overlapping part from our AI suggestion's ghost text to avoid
629
+ // showing a double suggestion.
630
+ const currentMenuHint = update.view.plugin(showCompletionHint)?.currentHint;
631
+ const conservativeCompletionEnabled = update.state.field(conservativeCompletion, false);
632
+ if (!conservativeCompletionEnabled && currentMenuHint) {
633
+ ghostText = ghostText.slice(currentMenuHint.length);
634
+ }
635
+
636
+ this.decorations =
637
+ CM.Decoration.set([CM.Decoration.widget({widget: new CompletionHint(ghostText), side: 1}).range(head)]);
588
638
  }
589
639
  },
590
640
  {decorations: p => p.decorations}),
@@ -21,8 +21,8 @@ export class Dialog extends Common.ObjectWrapper.eventMixin<EventTypes, typeof G
21
21
  private focusRestorer: WidgetFocusRestorer|null = null;
22
22
  private closeOnEscape = true;
23
23
  private targetDocument: Document|null = null;
24
- private readonly targetDocumentKeyDownHandler: (event: Event) => void;
25
- private escapeKeyCallback: ((arg0: Event) => void)|null = null;
24
+ private readonly targetDocumentKeyDownHandler: (event: KeyboardEvent) => void;
25
+ private escapeKeyCallback: ((arg0: KeyboardEvent) => void)|null = null;
26
26
 
27
27
  constructor(jslogContext?: string) {
28
28
  super();
@@ -36,6 +36,12 @@ export class Dialog extends Common.ObjectWrapper.eventMixin<EventTypes, typeof G
36
36
  this.widget().setDefaultFocusedElement(this.contentElement);
37
37
  this.setPointerEventsBehavior(PointerEventsBehavior.BLOCKED_BY_GLASS_PANE);
38
38
  this.setOutsideClickCallback(event => {
39
+ // If there are stacked dialogs, we only want to
40
+ // handle the outside click for the top most dialog.
41
+ if (Dialog.getInstance() !== this) {
42
+ return;
43
+ }
44
+
39
45
  this.hide();
40
46
  event.consume(true);
41
47
  });
@@ -44,22 +50,35 @@ export class Dialog extends Common.ObjectWrapper.eventMixin<EventTypes, typeof G
44
50
  }
45
51
 
46
52
  static hasInstance(): boolean {
47
- return Boolean(Dialog.instance);
53
+ return Dialog.dialogs.length > 0;
48
54
  }
49
55
 
56
+ /**
57
+ * If there is only one dialog, returns that.
58
+ * If there are stacked dialogs, returns the topmost one.
59
+ */
50
60
  static getInstance(): Dialog|null {
51
- return Dialog.instance;
61
+ return Dialog.dialogs[Dialog.dialogs.length - 1] || null;
52
62
  }
53
63
 
54
- override show(where?: Document|Element): void {
64
+ /**
65
+ * `stack` parameter is needed for being able to open a dialog on top
66
+ * of an existing dialog. The main reason is, Settings Tab is
67
+ * implemented as a Dialog. So, if we want to open a dialog on the
68
+ * Settings Tab, we need to stack it on top of that dialog.
69
+ *
70
+ * @param where Container element of the dialog.
71
+ * @param stack Whether to open this dialog on top of an existing dialog.
72
+ */
73
+ override show(where?: Document|Element, stack?: boolean): void {
55
74
  const document = (where instanceof Document ? where : (where || InspectorView.instance().element).ownerDocument);
56
75
  this.targetDocument = document;
57
76
  this.targetDocument.addEventListener('keydown', this.targetDocumentKeyDownHandler, true);
58
77
 
59
- if (Dialog.instance) {
60
- Dialog.instance.hide();
78
+ if (!stack && Dialog.dialogs.length) {
79
+ Dialog.dialogs.forEach(dialog => dialog.hide());
61
80
  }
62
- Dialog.instance = this;
81
+ Dialog.dialogs.push(this);
63
82
  this.disableTabIndexOnElements(document);
64
83
  super.show(document);
65
84
  this.focusRestorer = new WidgetFocusRestorer(this.widget());
@@ -76,7 +95,10 @@ export class Dialog extends Common.ObjectWrapper.eventMixin<EventTypes, typeof G
76
95
  }
77
96
  this.restoreTabIndexOnElements();
78
97
  this.dispatchEventToListeners(Events.HIDDEN);
79
- Dialog.instance = null;
98
+ const index = Dialog.dialogs.indexOf(this);
99
+ if (index !== -1) {
100
+ Dialog.dialogs.splice(index, 1);
101
+ }
80
102
  }
81
103
 
82
104
  setAriaLabel(label: string): void {
@@ -87,7 +109,7 @@ export class Dialog extends Common.ObjectWrapper.eventMixin<EventTypes, typeof G
87
109
  this.closeOnEscape = close;
88
110
  }
89
111
 
90
- setEscapeKeyCallback(callback: (arg0: Event) => void): void {
112
+ setEscapeKeyCallback(callback: (arg0: KeyboardEvent) => void): void {
91
113
  this.escapeKeyCallback = callback;
92
114
  }
93
115
 
@@ -165,8 +187,11 @@ export class Dialog extends Common.ObjectWrapper.eventMixin<EventTypes, typeof G
165
187
  this.tabIndexMap.clear();
166
188
  }
167
189
 
168
- private onKeyDown(event: Event): void {
169
- const keyboardEvent = (event as KeyboardEvent);
190
+ private onKeyDown(event: KeyboardEvent): void {
191
+ const keyboardEvent = event;
192
+ if (Dialog.getInstance() !== this) {
193
+ return;
194
+ }
170
195
  if (keyboardEvent.keyCode === Keys.Esc.code && KeyboardShortcut.hasNoModifiers(event)) {
171
196
  if (this.escapeKeyCallback) {
172
197
  this.escapeKeyCallback(event);
@@ -183,7 +208,7 @@ export class Dialog extends Common.ObjectWrapper.eventMixin<EventTypes, typeof G
183
208
  }
184
209
  }
185
210
 
186
- private static instance: Dialog|null = null;
211
+ private static dialogs: Dialog[] = [];
187
212
  }
188
213
 
189
214
  export const enum Events {
@@ -136,7 +136,7 @@ export class InspectorView extends VBox implements ViewLocationResolver {
136
136
  private infoBarDiv!: HTMLDivElement|null;
137
137
  private readonly tabbedLocation: TabbedViewLocation;
138
138
  readonly tabbedPane: TabbedPane;
139
- private readonly keyDownBound: (event: Event) => void;
139
+ private readonly keyDownBound: (event: KeyboardEvent) => void;
140
140
  private currentPanelLocked?: boolean;
141
141
  private focusRestorer?: WidgetFocusRestorer|null;
142
142
  private ownerSplitWidget?: SplitWidget;
@@ -476,9 +476,8 @@ export class InspectorView extends VBox implements ViewLocationResolver {
476
476
  return this.drawerSplitWidget.isVertical();
477
477
  }
478
478
 
479
- private keyDown(event: Event): void {
480
- const keyboardEvent = (event as KeyboardEvent);
481
- if (!KeyboardShortcut.eventHasCtrlEquivalentKey(keyboardEvent) || keyboardEvent.altKey || keyboardEvent.shiftKey) {
479
+ private keyDown(event: KeyboardEvent): void {
480
+ if (!KeyboardShortcut.eventHasCtrlEquivalentKey(event) || event.altKey || event.shiftKey) {
482
481
  return;
483
482
  }
484
483
 
@@ -486,12 +485,11 @@ export class InspectorView extends VBox implements ViewLocationResolver {
486
485
  const panelShortcutEnabled = Common.Settings.moduleSetting('shortcut-panel-switch').get();
487
486
  if (panelShortcutEnabled) {
488
487
  let panelIndex = -1;
489
- if (keyboardEvent.keyCode > 0x30 && keyboardEvent.keyCode < 0x3A) {
490
- panelIndex = keyboardEvent.keyCode - 0x31;
488
+ if (event.keyCode > 0x30 && event.keyCode < 0x3A) {
489
+ panelIndex = event.keyCode - 0x31;
491
490
  } else if (
492
- keyboardEvent.keyCode > 0x60 && keyboardEvent.keyCode < 0x6A &&
493
- keyboardEvent.location === KeyboardEvent.DOM_KEY_LOCATION_NUMPAD) {
494
- panelIndex = keyboardEvent.keyCode - 0x61;
491
+ event.keyCode > 0x60 && event.keyCode < 0x6A && event.location === KeyboardEvent.DOM_KEY_LOCATION_NUMPAD) {
492
+ panelIndex = event.keyCode - 0x61;
495
493
  }
496
494
  if (panelIndex !== -1) {
497
495
  const panelName = this.tabbedPane.tabIds()[panelIndex];
@@ -12,7 +12,7 @@ export class ProgressIndicator extends HTMLElement implements Common.Progress.Pr
12
12
  readonly #contentElement: Element;
13
13
  #labelElement: Element;
14
14
  #progressElement: HTMLProgressElement;
15
- readonly #stopButton?: Element;
15
+ #stopButton?: Element;
16
16
  #isCanceled = false;
17
17
  #worked = 0;
18
18
  #isDone = false;
@@ -25,7 +25,10 @@ export class ProgressIndicator extends HTMLElement implements Common.Progress.Pr
25
25
  this.#labelElement = this.#contentElement.createChild('div', 'title');
26
26
  this.#progressElement = this.#contentElement.createChild('progress');
27
27
  this.#progressElement.value = 0;
28
+ }
28
29
 
30
+ connectedCallback(): void {
31
+ this.classList.add('progress-indicator');
29
32
  // By default we show the stop button, but this can be controlled by
30
33
  // using the 'no-stop-button' attribute on the element.
31
34
  if (!this.hasAttribute('no-stop-button')) {
@@ -34,10 +37,6 @@ export class ProgressIndicator extends HTMLElement implements Common.Progress.Pr
34
37
  }
35
38
  }
36
39
 
37
- connectedCallback(): void {
38
- this.classList.add('progress-indicator');
39
- }
40
-
41
40
  done(): void {
42
41
  if (this.#isDone) {
43
42
  return;