chrome-devtools-frontend 1.0.1021582 → 1.0.1022475

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 (49) hide show
  1. package/.eslintignore +14 -1
  2. package/extension-api/ExtensionAPI.d.ts +54 -4
  3. package/front_end/.eslintrc.js +3 -1
  4. package/front_end/core/host/InspectorFrontendHostAPI.ts +1 -0
  5. package/front_end/core/host/UserMetrics.ts +18 -0
  6. package/front_end/core/i18n/locales/en-US.json +60 -0
  7. package/front_end/core/i18n/locales/en-XL.json +60 -0
  8. package/front_end/core/sdk/DebuggerModel.ts +10 -0
  9. package/front_end/devtools_compatibility.js +1 -0
  10. package/front_end/legacy_test_runner/sources_test_runner/DebuggerTestRunner.js +4 -3
  11. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +166 -117
  12. package/front_end/models/bindings/ResourceScriptMapping.ts +12 -1
  13. package/front_end/models/extensions/ExtensionAPI.ts +101 -13
  14. package/front_end/models/extensions/ExtensionServer.ts +63 -1
  15. package/front_end/models/extensions/LanguageExtensionEndpoint.ts +16 -3
  16. package/front_end/models/issues_manager/RelatedIssue.ts +1 -1
  17. package/front_end/models/issues_manager/descriptions/federatedAuthRequestErrorIdToken.md +1 -1
  18. package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -1
  19. package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -1
  20. package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -1
  21. package/front_end/models/timeline_model/TimelineModel.ts +164 -7
  22. package/front_end/panels/application/AppManifestView.ts +13 -2
  23. package/front_end/panels/application/ApplicationPanelSidebar.ts +67 -5
  24. package/front_end/panels/elements/ElementsTreeOutline.ts +41 -7
  25. package/front_end/panels/elements/TopLayerContainer.ts +9 -1
  26. package/front_end/panels/elements/components/AdornerManager.ts +7 -0
  27. package/front_end/panels/elements/elementsTreeOutline.css +4 -0
  28. package/front_end/panels/network/components/RequestHeadersView.css +55 -0
  29. package/front_end/panels/network/components/RequestHeadersView.ts +278 -14
  30. package/front_end/panels/sources/AddSourceMapURLDialog.ts +17 -3
  31. package/front_end/panels/sources/CallStackSidebarPane.ts +7 -0
  32. package/front_end/panels/sources/DebuggerPlugin.ts +29 -3
  33. package/front_end/panels/sources/ScopeChainSidebarPane.ts +8 -0
  34. package/front_end/panels/sources/SourcesPanel.ts +14 -0
  35. package/front_end/third_party/acorn/acorn.ts +1 -1
  36. package/front_end/third_party/chromium/client-variations/client-variations.ts +1 -1
  37. package/front_end/third_party/diff/DiffWrapper.ts +2 -0
  38. package/front_end/third_party/i18n/i18n-impl.ts +5 -1
  39. package/front_end/third_party/i18n/i18n.ts +1 -1
  40. package/front_end/third_party/i18n/locales.ts +1 -1
  41. package/front_end/third_party/marked/marked.ts +1 -1
  42. package/front_end/third_party/puppeteer/puppeteer.ts +6 -6
  43. package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspectorController.ts +23 -1
  44. package/front_end/ui/legacy/ReportView.ts +8 -0
  45. package/package.json +1 -1
  46. package/scripts/eslint_rules/lib/custom_element_definitions_location.js +29 -14
  47. package/scripts/eslint_rules/lib/es_modules_import.js +5 -1
  48. package/scripts/eslint_rules/tests/custom_element_definitions_location_test.js +14 -2
  49. package/scripts/eslint_rules/tests/es_modules_import_test.js +5 -0
@@ -55,6 +55,7 @@ import {LanguageExtensionEndpoint} from './LanguageExtensionEndpoint.js';
55
55
  import {RecorderExtensionEndpoint} from './RecorderExtensionEndpoint.js';
56
56
  import {PrivateAPI} from './ExtensionAPI.js';
57
57
  import {RecorderPluginManager} from './RecorderPluginManager.js';
58
+ import type {Chrome} from '../../../extension-api/ExtensionAPI.js'; // eslint-disable-line rulesdir/es_modules_import
58
59
 
59
60
  const extensionOrigins: WeakMap<MessagePort, Platform.DevToolsPath.UrlString> = new WeakMap();
60
61
 
@@ -140,6 +141,10 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
140
141
  this.registerHandler(PrivateAPI.Commands.UpdateButton, this.onUpdateButton.bind(this));
141
142
  this.registerHandler(
142
143
  PrivateAPI.Commands.RegisterLanguageExtensionPlugin, this.registerLanguageExtensionEndpoint.bind(this));
144
+ this.registerHandler(PrivateAPI.Commands.GetWasmLinearMemory, this.onGetWasmLinearMemory.bind(this));
145
+ this.registerHandler(PrivateAPI.Commands.GetWasmGlobal, this.onGetWasmGlobal.bind(this));
146
+ this.registerHandler(PrivateAPI.Commands.GetWasmLocal, this.onGetWasmLocal.bind(this));
147
+ this.registerHandler(PrivateAPI.Commands.GetWasmOp, this.onGetWasmOp.bind(this));
143
148
  this.registerHandler(
144
149
  PrivateAPI.Commands.RegisterRecorderExtensionPlugin, this.registerRecorderExtensionEndpoint.bind(this));
145
150
  window.addEventListener('message', this.onWindowMessage.bind(this), false); // Only for main window.
@@ -204,7 +209,7 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
204
209
  private registerLanguageExtensionEndpoint(
205
210
  message: PrivateAPI.ExtensionServerRequestMessage, _shared_port: MessagePort): Record {
206
211
  if (message.command !== PrivateAPI.Commands.RegisterLanguageExtensionPlugin) {
207
- return this.status.E_BADARG('command', `expected ${PrivateAPI.Commands.Subscribe}`);
212
+ return this.status.E_BADARG('command', `expected ${PrivateAPI.Commands.RegisterLanguageExtensionPlugin}`);
208
213
  }
209
214
  const {pluginManager} = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
210
215
  if (!pluginManager) {
@@ -219,6 +224,63 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
219
224
  return this.status.OK();
220
225
  }
221
226
 
227
+ private async loadWasmValue<T>(expression: string, stopId: unknown): Promise<Record|T> {
228
+ const {pluginManager} = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
229
+ if (!pluginManager) {
230
+ return this.status.E_FAILED('WebAssembly DWARF support needs to be enabled to use this extension');
231
+ }
232
+
233
+ const callFrame = pluginManager.callFrameForStopId(stopId as Bindings.DebuggerLanguagePlugins.StopId);
234
+ if (!callFrame) {
235
+ return this.status.E_BADARG('stopId', 'Unknown stop id');
236
+ }
237
+ const result = await callFrame.debuggerModel.agent.invoke_evaluateOnCallFrame({
238
+ callFrameId: callFrame.id,
239
+ expression,
240
+ silent: true,
241
+ returnByValue: true,
242
+ throwOnSideEffect: true,
243
+ });
244
+
245
+ if (!result.exceptionDetails && !result.getError()) {
246
+ return result.result.value;
247
+ }
248
+
249
+ return this.status.E_FAILED('Failed');
250
+ }
251
+
252
+ private async onGetWasmLinearMemory(message: PrivateAPI.ExtensionServerRequestMessage): Promise<Record|number[]> {
253
+ if (message.command !== PrivateAPI.Commands.GetWasmLinearMemory) {
254
+ return this.status.E_BADARG('command', `expected ${PrivateAPI.Commands.GetWasmLinearMemory}`);
255
+ }
256
+ return await this.loadWasmValue<number[]>(
257
+ `[].slice.call(new Uint8Array(memories[0].buffer, ${Number(message.offset)}, ${Number(message.length)}))`,
258
+ message.stopId);
259
+ }
260
+
261
+ private async onGetWasmGlobal(message: PrivateAPI.ExtensionServerRequestMessage):
262
+ Promise<Record|Chrome.DevTools.WasmValue> {
263
+ if (message.command !== PrivateAPI.Commands.GetWasmGlobal) {
264
+ return this.status.E_BADARG('command', `expected ${PrivateAPI.Commands.GetWasmGlobal}`);
265
+ }
266
+ return this.loadWasmValue(`globals[${Number(message.global)}]`, message.stopId);
267
+ }
268
+
269
+ private async onGetWasmLocal(message: PrivateAPI.ExtensionServerRequestMessage):
270
+ Promise<Record|Chrome.DevTools.WasmValue> {
271
+ if (message.command !== PrivateAPI.Commands.GetWasmLocal) {
272
+ return this.status.E_BADARG('command', `expected ${PrivateAPI.Commands.GetWasmLocal}`);
273
+ }
274
+ return this.loadWasmValue(`locals[${Number(message.local)}]`, message.stopId);
275
+ }
276
+ private async onGetWasmOp(message: PrivateAPI.ExtensionServerRequestMessage):
277
+ Promise<Record|Chrome.DevTools.WasmValue> {
278
+ if (message.command !== PrivateAPI.Commands.GetWasmOp) {
279
+ return this.status.E_BADARG('command', `expected ${PrivateAPI.Commands.GetWasmOp}`);
280
+ }
281
+ return this.loadWasmValue(`stack[${Number(message.op)}]`, message.stopId);
282
+ }
283
+
222
284
  private registerRecorderExtensionEndpoint(
223
285
  message: PrivateAPI.ExtensionServerRequestMessage, _shared_port: MessagePort): Record {
224
286
  if (message.command !== PrivateAPI.Commands.RegisterRecorderExtensionPlugin) {
@@ -29,7 +29,7 @@ class LanguageExtensionEndpointImpl extends ExtensionEndpoint {
29
29
  }
30
30
  }
31
31
 
32
- export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.DebuggerLanguagePlugin {
32
+ export class LanguageExtensionEndpoint implements Bindings.DebuggerLanguagePlugins.DebuggerLanguagePlugin {
33
33
  private readonly supportedScriptTypes: {
34
34
  language: string,
35
35
  // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
@@ -37,6 +37,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
37
37
  symbol_types: Array<string>,
38
38
  };
39
39
  private endpoint: LanguageExtensionEndpointImpl;
40
+ name: string;
41
+
40
42
  constructor(
41
43
  name: string, supportedScriptTypes: {
42
44
  language: string,
@@ -45,7 +47,7 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
45
47
  symbol_types: Array<string>,
46
48
  },
47
49
  port: MessagePort) {
48
- super(name);
50
+ this.name = name;
49
51
  this.supportedScriptTypes = supportedScriptTypes;
50
52
  this.endpoint = new LanguageExtensionEndpointImpl(this, port);
51
53
  }
@@ -172,6 +174,17 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
172
174
  PrivateAPI.LanguageExtensionPluginCommands.GetMappedLines, {rawModuleId, sourceFileURL});
173
175
  }
174
176
 
175
- dispose(): void {
177
+ evaluate(expression: string, context: Chrome.DevTools.RawLocation, stopId: number):
178
+ Promise<Chrome.DevTools.RemoteObject> {
179
+ return this.endpoint.sendRequest(
180
+ PrivateAPI.LanguageExtensionPluginCommands.FormatValue, {expression, context, stopId});
181
+ }
182
+
183
+ getProperties(objectId: Chrome.DevTools.RemoteObjectId): Promise<Chrome.DevTools.PropertyDescriptor[]> {
184
+ return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetProperties, {objectId});
185
+ }
186
+
187
+ releaseObject(objectId: Chrome.DevTools.RemoteObjectId): Promise<void> {
188
+ return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.ReleaseObject, {objectId});
176
189
  }
177
190
  }
@@ -7,7 +7,7 @@ import * as SDK from '../../core/sdk/sdk.js';
7
7
  import type {Issue, IssueCategory} from './Issue.js';
8
8
  import {IssuesManager} from './IssuesManager.js';
9
9
 
10
- export type IssuesAssociatable = SDK.NetworkRequest.NetworkRequest|SDK.Cookie.Cookie|string;
10
+ export type IssuesAssociatable = Readonly<SDK.NetworkRequest.NetworkRequest>|SDK.Cookie.Cookie|string;
11
11
 
12
12
  function issuesAssociatedWithNetworkRequest(issues: Issue[], request: SDK.NetworkRequest.NetworkRequest): Issue[] {
13
13
  return issues.filter(issue => {
@@ -1 +1 @@
1
- # Error retrieving an id token.
1
+ # Error retrieving a token.
@@ -1 +1 @@
1
- # The id token fetching request is invalid.
1
+ # The token fetching request is invalid.
@@ -1 +1 @@
1
- # Provider's id token is invalid.
1
+ # Provider's token is invalid.
@@ -1 +1 @@
1
- # The response body is empty when fetching the provider's id token.
1
+ # The response body is empty when fetching the provider's token.
@@ -61,6 +61,39 @@ const UIStrings = {
61
61
  *@example {https://google.com} PH2
62
62
  */
63
63
  workerSS: '`Worker`: {PH1} — {PH2}',
64
+
65
+ /**
66
+ *@description Title of a bidder auction worklet with known URL in the timeline flame chart of the Performance panel
67
+ *@example {https://google.com} PH1
68
+ */
69
+ bidderWorkletS: 'Bidder Worklet — {PH1}',
70
+
71
+ /**
72
+ *@description Title of a seller auction worklet with known URL in the timeline flame chart of the Performance panel
73
+ *@example {https://google.com} PH1
74
+ */
75
+ sellerWorkletS: 'Seller Worklet — {PH1}',
76
+
77
+ /**
78
+ *@description Title of an auction worklet with known URL in the timeline flame chart of the Performance panel
79
+ *@example {https://google.com} PH1
80
+ */
81
+ unknownWorkletS: 'Auction Worklet — {PH1}',
82
+
83
+ /**
84
+ *@description Title of a bidder auction worklet in the timeline flame chart of the Performance panel
85
+ */
86
+ bidderWorklet: 'Bidder Worklet',
87
+
88
+ /**
89
+ *@description Title of a seller auction worklet in the timeline flame chart of the Performance panel
90
+ */
91
+ sellerWorklet: 'Seller Worklet',
92
+
93
+ /**
94
+ *@description Title of an auction worklet in the timeline flame chart of the Performance panel
95
+ */
96
+ unknownWorklet: 'Auction Worklet',
64
97
  };
65
98
  const str_ = i18n.i18n.registerUIStrings('models/timeline_model/TimelineModel.ts', UIStrings);
66
99
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -73,6 +106,7 @@ export class TimelineModelImpl {
73
106
  private sessionId!: string|null;
74
107
  private mainFrameNodeId!: number|null;
75
108
  private pageFrames!: Map<Protocol.Page.FrameId, PageFrame>;
109
+ private auctionWorklets!: Map<string, AuctionWorklet>;
76
110
  private cpuProfilesInternal!: SDK.CPUProfileDataModel.CPUProfileDataModel[];
77
111
  private workerIdByThread!: WeakMap<SDK.TracingModel.Thread, string>;
78
112
  private requestsFromBrowser!: Map<string, SDK.TracingModel.Event>;
@@ -327,7 +361,8 @@ export class TimelineModelImpl {
327
361
  for (const process of tracingModel.sortedProcesses()) {
328
362
  for (const thread of process.sortedThreads()) {
329
363
  this.processThreadEvents(
330
- tracingModel, [{from: 0, to: Infinity}], thread, thread === browserMainThread, false, true, null);
364
+ tracingModel, [{from: 0, to: Infinity}], thread, thread === browserMainThread, false, true,
365
+ WorkletType.NotWorklet, null);
331
366
  }
332
367
  }
333
368
  }
@@ -368,7 +403,7 @@ export class TimelineModelImpl {
368
403
  }
369
404
  this.processThreadEvents(
370
405
  tracingModel, [{from: startTime, to: endTime}], thread, thread === metaEvent.thread, Boolean(workerUrl),
371
- true, workerUrl);
406
+ true, WorkletType.NotWorklet, workerUrl);
372
407
  }
373
408
  startTime = endTime;
374
409
  }
@@ -379,6 +414,7 @@ export class TimelineModelImpl {
379
414
  from: number,
380
415
  to: number,
381
416
  main: boolean,
417
+ workletType: WorkletType,
382
418
  url: Platform.DevToolsPath.UrlString,
383
419
  }[]>();
384
420
  for (const frame of this.pageFrames.values()) {
@@ -390,9 +426,32 @@ export class TimelineModelImpl {
390
426
  processData.set(pid, data);
391
427
  }
392
428
  const to = i === frame.processes.length - 1 ? (frame.deletedTime || Infinity) : frame.processes[i + 1].time;
393
- data.push({from: frame.processes[i].time, to: to, main: !frame.parent, url: frame.processes[i].url});
429
+ data.push({
430
+ from: frame.processes[i].time,
431
+ to: to,
432
+ main: !frame.parent,
433
+ url: frame.processes[i].url,
434
+ workletType: WorkletType.NotWorklet,
435
+ });
394
436
  }
395
437
  }
438
+ for (const auctionWorklet of this.auctionWorklets.values()) {
439
+ const pid = auctionWorklet.processId;
440
+ let data = processData.get(pid);
441
+ if (!data) {
442
+ data = [];
443
+ processData.set(pid, data);
444
+ }
445
+ data.push({
446
+ from: auctionWorklet.startTime,
447
+ to: auctionWorklet.endTime,
448
+ main: false,
449
+ workletType: auctionWorklet.workletType,
450
+ url:
451
+ (auctionWorklet.host ? 'https://' + auctionWorklet.host as Platform.DevToolsPath.UrlString :
452
+ Platform.DevToolsPath.EmptyUrlString),
453
+ });
454
+ }
396
455
  const allMetadataEvents = tracingModel.devToolsMetadataEvents();
397
456
  for (const process of tracingModel.sortedProcesses()) {
398
457
  const data = processData.get(process.id());
@@ -404,6 +463,12 @@ export class TimelineModelImpl {
404
463
  let lastUrl: Platform.DevToolsPath.UrlString|null = null;
405
464
  let lastMainUrl: Platform.DevToolsPath.UrlString|null = null;
406
465
  let hasMain = false;
466
+ let allWorklet = true;
467
+
468
+ // false: not set, true: inconsistent.
469
+ let workletUrl: Platform.DevToolsPath.UrlString|boolean = false;
470
+ // NotWorklet used for not set.
471
+ let workletType: WorkletType = WorkletType.NotWorklet;
407
472
  for (const item of data) {
408
473
  const last = ranges[ranges.length - 1];
409
474
  if (!last || item.from > last.to) {
@@ -414,6 +479,23 @@ export class TimelineModelImpl {
414
479
  if (item.main) {
415
480
  hasMain = true;
416
481
  }
482
+ if (item.workletType === WorkletType.NotWorklet) {
483
+ allWorklet = false;
484
+ } else {
485
+ // Update combined workletUrl, checking for inconsistencies.
486
+ if (workletUrl === false) {
487
+ workletUrl = item.url;
488
+ } else if (workletUrl !== item.url) {
489
+ workletUrl = true; // Process used for different things.
490
+ }
491
+
492
+ if (workletType === WorkletType.NotWorklet) {
493
+ workletType = item.workletType;
494
+ } else if (workletType !== item.workletType) {
495
+ workletType = WorkletType.UnknownWorklet;
496
+ }
497
+ }
498
+
417
499
  if (item.url) {
418
500
  if (item.main) {
419
501
  lastMainUrl = item.url;
@@ -426,7 +508,7 @@ export class TimelineModelImpl {
426
508
  if (thread.name() === TimelineModelImpl.RendererMainThreadName) {
427
509
  this.processThreadEvents(
428
510
  tracingModel, ranges, thread, true /* isMainThread */, false /* isWorker */, hasMain,
429
- hasMain ? lastMainUrl : lastUrl);
511
+ WorkletType.NotWorklet, hasMain ? lastMainUrl : lastUrl);
430
512
  } else if (
431
513
  thread.name() === TimelineModelImpl.WorkerThreadName ||
432
514
  thread.name() === TimelineModelImpl.WorkerThreadNameLegacy) {
@@ -449,11 +531,24 @@ export class TimelineModelImpl {
449
531
  this.workerIdByThread.set(thread, workerMetaEvent.args['data']['workerId'] || '');
450
532
  this.processThreadEvents(
451
533
  tracingModel, ranges, thread, false /* isMainThread */, true /* isWorker */, false /* forMainFrame */,
452
- workerMetaEvent.args['data']['url'] || Platform.DevToolsPath.EmptyUrlString);
534
+ WorkletType.NotWorklet, workerMetaEvent.args['data']['url'] || Platform.DevToolsPath.EmptyUrlString);
453
535
  } else {
536
+ let urlForOther: Platform.DevToolsPath.UrlString|null = null;
537
+ let workletTypeForOther: WorkletType = WorkletType.NotWorklet;
538
+ if (thread.name() === TimelineModelImpl.AuctionWorkletThreadName) {
539
+ if (typeof workletUrl !== 'boolean') {
540
+ urlForOther = workletUrl;
541
+ }
542
+ workletTypeForOther = workletType;
543
+ } else {
544
+ // For processes that only do auction worklet things, skip other threads.
545
+ if (allWorklet) {
546
+ continue;
547
+ }
548
+ }
454
549
  this.processThreadEvents(
455
550
  tracingModel, ranges, thread, false /* isMainThread */, false /* isWorker */, false /* forMainFrame */,
456
- null);
551
+ workletTypeForOther, urlForOther);
457
552
  }
458
553
  }
459
554
  }
@@ -690,13 +785,26 @@ export class TimelineModelImpl {
690
785
  return events;
691
786
  }
692
787
 
788
+ private static nameAuctionWorklet(workletType: WorkletType, url: Platform.DevToolsPath.UrlString|null): string {
789
+ switch (workletType) {
790
+ case WorkletType.BidderWorklet:
791
+ return url ? i18nString(UIStrings.bidderWorkletS, {PH1: url}) : i18nString(UIStrings.bidderWorklet);
792
+
793
+ case WorkletType.SellerWorklet:
794
+ return url ? i18nString(UIStrings.sellerWorkletS, {PH1: url}) : i18nString(UIStrings.sellerWorklet);
795
+
796
+ default:
797
+ return url ? i18nString(UIStrings.unknownWorkletS, {PH1: url}) : i18nString(UIStrings.unknownWorklet);
798
+ }
799
+ }
800
+
693
801
  private processThreadEvents(
694
802
  tracingModel: SDK.TracingModel.TracingModel, ranges: {
695
803
  from: number,
696
804
  to: number,
697
805
  }[],
698
806
  thread: SDK.TracingModel.Thread, isMainThread: boolean, isWorker: boolean, forMainFrame: boolean,
699
- url: Platform.DevToolsPath.UrlString|null): void {
807
+ workletType: WorkletType, url: Platform.DevToolsPath.UrlString|null): void {
700
808
  const track = new Track();
701
809
  track.name = thread.name() || i18nString(UIStrings.threadS, {PH1: thread.id()});
702
810
  track.type = TrackType.Other;
@@ -711,6 +819,9 @@ export class TimelineModelImpl {
711
819
  track.name = track.url ? i18nString(UIStrings.workerS, {PH1: track.url}) : i18nString(UIStrings.dedicatedWorker);
712
820
  } else if (thread.name().startsWith('CompositorTileWorker')) {
713
821
  track.type = TrackType.Raster;
822
+ } else if (thread.name() === TimelineModelImpl.AuctionWorkletThreadName) {
823
+ track.url = url || Platform.DevToolsPath.EmptyUrlString;
824
+ track.name = TimelineModelImpl.nameAuctionWorklet(workletType, url);
714
825
  }
715
826
  this.tracksInternal.push(track);
716
827
 
@@ -1239,6 +1350,18 @@ export class TimelineModelImpl {
1239
1350
  }
1240
1351
  return;
1241
1352
  }
1353
+ if (event.name === TimelineModelImpl.DevToolsMetadataEvent.AuctionWorkletRunningInProcess &&
1354
+ this.browserFrameTracking) {
1355
+ const worklet = new AuctionWorklet(event, data);
1356
+ this.auctionWorklets.set(data['target'], worklet);
1357
+ }
1358
+ if (event.name === TimelineModelImpl.DevToolsMetadataEvent.AuctionWorkletDoneWithProcess &&
1359
+ this.browserFrameTracking) {
1360
+ const worklet = this.auctionWorklets.get(data['target']);
1361
+ if (worklet) {
1362
+ worklet.endTime = event.startTime;
1363
+ }
1364
+ }
1242
1365
  }
1243
1366
  }
1244
1367
 
@@ -1290,6 +1413,7 @@ export class TimelineModelImpl {
1290
1413
  this.cpuProfilesInternal = [];
1291
1414
  this.workerIdByThread = new WeakMap();
1292
1415
  this.pageFrames = new Map();
1416
+ this.auctionWorklets = new Map();
1293
1417
  this.requestsFromBrowser = new Map();
1294
1418
 
1295
1419
  this.minimumRecordTimeInternal = 0;
@@ -1576,6 +1700,7 @@ export namespace TimelineModelImpl {
1576
1700
  export const WorkerThreadNameLegacy = 'DedicatedWorker Thread';
1577
1701
  export const RendererMainThreadName = 'CrRendererMain';
1578
1702
  export const BrowserMainThreadName = 'CrBrowserMain';
1703
+ export const AuctionWorkletThreadName = 'AuctionV8HelperThread';
1579
1704
 
1580
1705
  export const DevToolsMetadataEvent = {
1581
1706
  TracingStartedInBrowser: 'TracingStartedInBrowser',
@@ -1584,6 +1709,8 @@ export namespace TimelineModelImpl {
1584
1709
  FrameCommittedInBrowser: 'FrameCommittedInBrowser',
1585
1710
  ProcessReadyInBrowser: 'ProcessReadyInBrowser',
1586
1711
  FrameDeletedInBrowser: 'FrameDeletedInBrowser',
1712
+ AuctionWorkletRunningInProcess: 'AuctionWorkletRunningInProcess',
1713
+ AuctionWorkletDoneWithProcess: 'AuctionWorkletDoneWithProcess',
1587
1714
  };
1588
1715
 
1589
1716
  export const Thresholds = {
@@ -1680,6 +1807,13 @@ export enum TrackType {
1680
1807
  Other = 'Other',
1681
1808
  }
1682
1809
 
1810
+ const enum WorkletType {
1811
+ NotWorklet = 0,
1812
+ BidderWorklet = 1,
1813
+ SellerWorklet = 2,
1814
+ UnknownWorklet = 3, // new type, or thread used for multiple ones.
1815
+ }
1816
+
1683
1817
  export class PageFrame {
1684
1818
  frameId: any;
1685
1819
  url: any;
@@ -1734,6 +1868,29 @@ export class PageFrame {
1734
1868
  }
1735
1869
  }
1736
1870
 
1871
+ export class AuctionWorklet {
1872
+ targetId: string;
1873
+ processId: number;
1874
+ host?: string;
1875
+ startTime: number;
1876
+ endTime: number;
1877
+ workletType: WorkletType;
1878
+ constructor(event: SDK.TracingModel.Event, data: any) {
1879
+ this.targetId = (typeof data['target'] === 'string') ? data['target'] : '';
1880
+ this.processId = (typeof data['pid'] === 'number') ? data['pid'] : 0;
1881
+ this.host = (typeof data['host'] === 'string') ? data['host'] : undefined;
1882
+ this.startTime = event.startTime;
1883
+ this.endTime = Infinity;
1884
+ if (data['type'] === 'bidder') {
1885
+ this.workletType = WorkletType.BidderWorklet;
1886
+ } else if (data['type'] === 'seller') {
1887
+ this.workletType = WorkletType.SellerWorklet;
1888
+ } else {
1889
+ this.workletType = WorkletType.UnknownWorklet;
1890
+ }
1891
+ }
1892
+ }
1893
+
1737
1894
  export class NetworkRequest {
1738
1895
  startTime: number;
1739
1896
  endTime: number;
@@ -408,6 +408,7 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
408
408
  private readonly identitySection: UI.ReportView.Section;
409
409
  private readonly presentationSection: UI.ReportView.Section;
410
410
  private readonly iconsSection: UI.ReportView.Section;
411
+ private readonly protocolHandlersSection: UI.ReportView.Section;
411
412
  private readonly shortcutSections: UI.ReportView.Section[];
412
413
  private readonly screenshotsSections: UI.ReportView.Section[];
413
414
  private nameField: HTMLElement;
@@ -455,9 +456,9 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
455
456
  this.installabilitySection = this.reportView.appendSection(i18nString(UIStrings.installability));
456
457
  this.identitySection = this.reportView.appendSection(i18nString(UIStrings.identity));
457
458
  this.presentationSection = this.reportView.appendSection(i18nString(UIStrings.presentation));
458
- const protocolHandlersSection = this.reportView.appendSection(i18nString(UIStrings.protocolHandlers));
459
+ this.protocolHandlersSection = this.reportView.appendSection(i18nString(UIStrings.protocolHandlers));
459
460
  this.protocolHandlersView = new ApplicationComponents.ProtocolHandlersView.ProtocolHandlersView();
460
- protocolHandlersSection.contentElement.append(this.protocolHandlersView);
461
+ this.protocolHandlersSection.contentElement.append(this.protocolHandlersView);
461
462
  this.iconsSection = this.reportView.appendSection(i18nString(UIStrings.icons), 'report-section-icons');
462
463
  this.shortcutSections = [];
463
464
  this.screenshotsSections = [];
@@ -494,6 +495,14 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
494
495
  this.registeredListeners = [];
495
496
  }
496
497
 
498
+ getStaticSections(): UI.ReportView.Section[] {
499
+ return [this.identitySection, this.presentationSection, this.protocolHandlersSection, this.iconsSection];
500
+ }
501
+
502
+ getManifestElement(): Element {
503
+ return this.reportView.getHeaderElement();
504
+ }
505
+
497
506
  targetAdded(target: SDK.Target.Target): void {
498
507
  if (this.target) {
499
508
  return;
@@ -559,10 +568,12 @@ export class AppManifestView extends UI.Widget.VBox implements SDK.TargetManager
559
568
  if (!data && !errors.length) {
560
569
  this.emptyView.showWidget();
561
570
  this.reportView.hideWidget();
571
+ this.contentElement.dispatchEvent(new CustomEvent('manifestDetection', {detail: false}));
562
572
  return;
563
573
  }
564
574
  this.emptyView.hideWidget();
565
575
  this.reportView.showWidget();
576
+ this.contentElement.dispatchEvent(new CustomEvent('manifestDetection', {detail: true}));
566
577
 
567
578
  const link = Components.Linkifier.Linkifier.linkifyURL(url);
568
579
  link.tabIndex = 0;
@@ -170,6 +170,20 @@ const UIStrings = {
170
170
  *@description Default name for worker
171
171
  */
172
172
  worker: 'worker',
173
+ /**
174
+ * @description Aria text for screen reader to announce they can scroll to top of manifest if invoked
175
+ */
176
+ onInvokeManifestAlert: 'Manifest: Invoke to scroll to the top of manifest',
177
+ /**
178
+ * @description Aria text for screen reader to announce they can scroll to a section if invoked
179
+ * @example {"Identity"} PH1
180
+ */
181
+ beforeInvokeAlert: '{PH1}: Invoke to scroll to this section in manifest',
182
+ /**
183
+ * @description Alert message for screen reader to announce which subsection is being scrolled to
184
+ * @example {"Identity"} PH1
185
+ */
186
+ onInvokeAlert: 'Scrolled to {PH1}',
173
187
  };
174
188
  const str_ = i18n.i18n.registerUIStrings('panels/application/ApplicationPanelSidebar.ts', UIStrings);
175
189
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
@@ -233,6 +247,7 @@ export class ApplicationPanelSidebar extends UI.Widget.VBox implements SDK.Targe
233
247
  this.applicationTreeElement = this.addSidebarSection(applicationSectionTitle);
234
248
  const manifestTreeElement = new AppManifestTreeElement(panel);
235
249
  this.applicationTreeElement.appendChild(manifestTreeElement);
250
+ manifestTreeElement.generateChildren();
236
251
  this.serviceWorkersTreeElement = new ServiceWorkersTreeElement(panel);
237
252
  this.applicationTreeElement.appendChild(this.serviceWorkersTreeElement);
238
253
  const clearStorageTreeElement = new ClearStorageTreeElement(panel);
@@ -930,11 +945,18 @@ export class ServiceWorkersTreeElement extends ApplicationPanelTreeElement {
930
945
  }
931
946
 
932
947
  export class AppManifestTreeElement extends ApplicationPanelTreeElement {
933
- private view?: AppManifestView;
948
+ private view: AppManifestView;
934
949
  constructor(storagePanel: ResourcesPanel) {
935
- super(storagePanel, i18nString(UIStrings.manifest), false);
950
+ super(storagePanel, i18nString(UIStrings.manifest), true);
936
951
  const icon = UI.Icon.Icon.create('mediumicon-manifest', 'resource-tree-item');
937
952
  this.setLeadingIcons([icon]);
953
+ self.onInvokeElement(this.listItemElement, this.onInvoke.bind(this));
954
+ this.view = new AppManifestView();
955
+ UI.ARIAUtils.setAccessibleName(this.listItemElement, i18nString(UIStrings.onInvokeManifestAlert));
956
+ const handleExpansion = (evt: Event): void => {
957
+ this.setExpandable((evt as CustomEvent).detail);
958
+ };
959
+ this.view.contentElement.addEventListener('manifestDetection', handleExpansion);
938
960
  }
939
961
 
940
962
  get itemURL(): Platform.DevToolsPath.UrlString {
@@ -943,13 +965,53 @@ export class AppManifestTreeElement extends ApplicationPanelTreeElement {
943
965
 
944
966
  onselect(selectedByUser?: boolean): boolean {
945
967
  super.onselect(selectedByUser);
946
- if (!this.view) {
947
- this.view = new AppManifestView();
948
- }
949
968
  this.showView(this.view);
950
969
  Host.userMetrics.panelShown(Host.UserMetrics.PanelCodes[Host.UserMetrics.PanelCodes.app_manifest]);
951
970
  return false;
952
971
  }
972
+
973
+ generateChildren(): void {
974
+ const staticSections = this.view.getStaticSections();
975
+ for (const section of staticSections) {
976
+ const sectionElement = section.getTitleElement();
977
+ const childTitle = section.title();
978
+ const child = new ManifestChildTreeElement(this.resourcesPanel, sectionElement, childTitle);
979
+ this.appendChild(child);
980
+ }
981
+ }
982
+
983
+ onInvoke(): void {
984
+ this.view.getManifestElement().scrollIntoView();
985
+ UI.ARIAUtils.alert(i18nString(UIStrings.onInvokeAlert, {PH1: this.listItemElement.title}));
986
+ }
987
+
988
+ showManifestView(): void {
989
+ this.showView(this.view);
990
+ }
991
+ }
992
+
993
+ export class ManifestChildTreeElement extends ApplicationPanelTreeElement {
994
+ #sectionElement: Element;
995
+ constructor(storagePanel: ResourcesPanel, element: Element, childTitle: string) {
996
+ super(storagePanel, childTitle, false);
997
+ const icon = UI.Icon.Icon.create('mediumicon-manifest', 'resource-tree-item');
998
+ this.setLeadingIcons([icon]);
999
+ this.#sectionElement = element;
1000
+ self.onInvokeElement(this.listItemElement, this.onInvoke.bind(this));
1001
+ UI.ARIAUtils.setAccessibleName(
1002
+ this.listItemElement, i18nString(UIStrings.beforeInvokeAlert, {PH1: this.listItemElement.title}));
1003
+ }
1004
+
1005
+ get itemURL(): Platform.DevToolsPath.UrlString {
1006
+ return 'manifest://' + this.title as Platform.DevToolsPath.UrlString;
1007
+ }
1008
+
1009
+ onInvoke(): void {
1010
+ (this.parent as AppManifestTreeElement)?.showManifestView();
1011
+ this.#sectionElement.scrollIntoView();
1012
+ UI.ARIAUtils.alert(i18nString(UIStrings.onInvokeAlert, {PH1: this.listItemElement.title}));
1013
+ Host.userMetrics.manifestSectionSelected(this.listItemElement.title);
1014
+ }
953
1015
  }
954
1016
 
955
1017
  export class ClearStorageTreeElement extends ApplicationPanelTreeElement {