chrome-devtools-frontend 1.0.1613625 → 1.0.1614363
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.
- package/AUTHORS +1 -0
- package/front_end/core/common/MapWithDefault.ts +2 -2
- package/front_end/core/common/Object.ts +6 -9
- package/front_end/core/common/VersionController.ts +17 -1
- package/front_end/core/host/UserMetrics.ts +0 -1
- package/front_end/core/root/ExperimentNames.ts +0 -1
- package/front_end/core/sdk/OverlayModel.ts +2 -4
- package/front_end/core/sdk/sdk-meta.ts +13 -0
- package/front_end/entrypoints/device_mode_emulation_frame/device_mode_emulation_frame.ts +4 -0
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -1
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -1
- package/front_end/entrypoints/main/MainImpl.ts +0 -6
- package/front_end/entrypoints/shell/shell.ts +4 -0
- package/front_end/entrypoints/trace_app/trace_app.ts +4 -0
- package/front_end/generated/InspectorBackendCommands.ts +2 -2
- package/front_end/generated/protocol.ts +5 -3
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +10 -2
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +23 -7
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +161 -36
- package/front_end/models/javascript_metadata/NativeFunctions.js +673 -639
- package/front_end/models/stack_trace/DetailedErrorStackParser.ts +142 -0
- package/front_end/models/stack_trace/StackTrace.ts +18 -0
- package/front_end/models/stack_trace/StackTraceImpl.ts +96 -4
- package/front_end/models/stack_trace/Trie.ts +21 -0
- package/front_end/models/stack_trace/stack_trace_impl.ts +2 -0
- package/front_end/panels/ai_assistance/components/ChatView.ts +4 -3
- package/front_end/panels/ai_assistance/components/ExportForAgentsDialog.ts +4 -1
- package/front_end/panels/ai_assistance/components/optInChangeDialog.css +1 -2
- package/front_end/panels/application/WebMCPView.ts +249 -17
- package/front_end/panels/application/components/ProtocolHandlersView.ts +2 -2
- package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +7 -0
- package/front_end/panels/console/ConsoleContextSelector.ts +1 -1
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +2 -3
- package/front_end/panels/css_overview/CSSOverviewModel.ts +1 -2
- package/front_end/panels/network/RequestConditionsDrawer.ts +4 -2
- package/front_end/panels/network/RequestPayloadView.ts +8 -3
- package/front_end/panels/network/RequestTimingView.ts +6 -7
- package/front_end/panels/performance_monitor/PerformanceMonitor.ts +7 -5
- package/front_end/panels/protocol_monitor/JSONEditor.ts +1 -1
- package/front_end/panels/recorder/models/RecordingPlayer.ts +1 -1
- package/front_end/services/puppeteer/PuppeteerConnection.ts +1 -1
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/codemirror/codemirror-tsconfig.json +4 -4
- package/front_end/third_party/lighthouse/lighthouse-tsconfig.json +1 -1
- package/front_end/tsconfig.json +2 -1
- package/front_end/ui/kit/icons/Icon.ts +0 -1
- package/front_end/ui/legacy/EmptyWidget.ts +2 -2
- package/front_end/ui/legacy/Treeoutline.ts +2 -3
- package/front_end/ui/legacy/components/color_picker/ContrastDetails.ts +1 -2
- package/front_end/ui/legacy/components/color_picker/ContrastOverlay.ts +4 -5
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -4
- package/front_end/ui/legacy/components/source_frame/XMLView.ts +12 -7
- package/front_end/ui/lit/lit.ts +4 -1
- package/front_end/ui/lit/render.ts +81 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -1
- package/package.json +2 -2
- /package/front_end/third_party/codemirror/package/addon/runmode/{runmode-standalone.mjs.d.ts → runmode-standalone.d.mts} +0 -0
- /package/front_end/third_party/codemirror/package/mode/css/{css.mjs.d.ts → css.d.mts} +0 -0
- /package/front_end/third_party/codemirror/package/mode/javascript/{javascript.mjs.d.ts → javascript.d.mts} +0 -0
- /package/front_end/third_party/codemirror/package/mode/xml/{xml.mjs.d.ts → xml.d.mts} +0 -0
- /package/front_end/third_party/lighthouse/report-assets/{report-generator.mjs.d.ts → report-generator.d.mts} +0 -0
package/AUTHORS
CHANGED
|
@@ -41,6 +41,7 @@ Emir D <emrd434@gmail.com>
|
|
|
41
41
|
Ergün Erdoğmuş <erdogmusergun@gmail.com>
|
|
42
42
|
Eric Rannaud <eric.rannaud@gmail.com>
|
|
43
43
|
Faisal Salman <fyzlman@gmail.com>
|
|
44
|
+
Fedor Indutny <indutny@signal.org>
|
|
44
45
|
Feng Lu <lufengd3@gmail.com>
|
|
45
46
|
Feng Yu <f3n67u@gmail.com>
|
|
46
47
|
Gabriel Luong <gabriel.luong@gmail.com>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* TODO: Once the proposal is merged, just replace `MapWithDefault` with `Map` and remove it.
|
|
9
9
|
**/
|
|
10
10
|
export class MapWithDefault<K, V> extends Map<K, V> {
|
|
11
|
-
|
|
11
|
+
getOrInsert(key: K, defaultValue: V): V {
|
|
12
12
|
if (!this.has(key)) {
|
|
13
13
|
this.set(key, defaultValue);
|
|
14
14
|
}
|
|
@@ -16,7 +16,7 @@ export class MapWithDefault<K, V> extends Map<K, V> {
|
|
|
16
16
|
return this.get(key) as V;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
getOrInsertComputed(key: K, callbackFunction: (key: K) => V): V {
|
|
20
20
|
if (!this.has(key)) {
|
|
21
21
|
this.set(key, callbackFunction(key));
|
|
22
22
|
}
|
|
@@ -119,34 +119,31 @@ export class ObjectWrapper<Events> implements EventTarget<Events> {
|
|
|
119
119
|
export function eventMixin<Events, Base extends Platform.Constructor.Constructor<object>>(base: Base) {
|
|
120
120
|
console.assert(base !== HTMLElement);
|
|
121
121
|
return class EventHandling extends base implements EventTarget<Events> {
|
|
122
|
-
|
|
123
|
-
// anonmous exported classes. We use a `__` prefix to prevent clashes with `base`.
|
|
124
|
-
// eslint-disable-next-line @devtools/no-underscored-properties, @typescript-eslint/naming-convention
|
|
125
|
-
__events = new ObjectWrapper<Events>();
|
|
122
|
+
#events = new ObjectWrapper<Events>();
|
|
126
123
|
|
|
127
124
|
addEventListener<T extends keyof Events>(
|
|
128
125
|
eventType: T, listener: (arg0: EventTargetEvent<Events[T]>) => void,
|
|
129
126
|
thisObject?: Object): EventDescriptor<Events, T> {
|
|
130
|
-
return this.
|
|
127
|
+
return this.#events.addEventListener(eventType, listener, thisObject);
|
|
131
128
|
}
|
|
132
129
|
|
|
133
130
|
once<T extends keyof Events>(eventType: T): Promise<Events[T]> {
|
|
134
|
-
return this.
|
|
131
|
+
return this.#events.once(eventType);
|
|
135
132
|
}
|
|
136
133
|
|
|
137
134
|
removeEventListener<T extends keyof Events>(
|
|
138
135
|
eventType: T, listener: (arg0: EventTargetEvent<Events[T]>) => void, thisObject?: Object): void {
|
|
139
|
-
this.
|
|
136
|
+
this.#events.removeEventListener(eventType, listener, thisObject);
|
|
140
137
|
}
|
|
141
138
|
|
|
142
139
|
hasEventListeners(eventType: keyof Events): boolean {
|
|
143
|
-
return this.
|
|
140
|
+
return this.#events.hasEventListeners(eventType);
|
|
144
141
|
}
|
|
145
142
|
|
|
146
143
|
dispatchEventToListeners<T extends keyof Events>(
|
|
147
144
|
eventType: Platform.TypeScriptUtilities.NoUnion<T>,
|
|
148
145
|
...eventData: EventPayloadToRestParameters<Events, T>): void {
|
|
149
|
-
this.
|
|
146
|
+
this.#events.dispatchEventToListeners(eventType, ...eventData);
|
|
150
147
|
}
|
|
151
148
|
};
|
|
152
149
|
}
|
|
@@ -17,7 +17,7 @@ export class VersionController {
|
|
|
17
17
|
static readonly SYNCED_VERSION_SETTING_NAME = 'syncedInspectorVersion';
|
|
18
18
|
static readonly LOCAL_VERSION_SETTING_NAME = 'localInspectorVersion';
|
|
19
19
|
|
|
20
|
-
static readonly CURRENT_VERSION =
|
|
20
|
+
static readonly CURRENT_VERSION = 44;
|
|
21
21
|
|
|
22
22
|
readonly #settings: Settings;
|
|
23
23
|
readonly #globalVersionSetting: Setting<number>;
|
|
@@ -848,6 +848,22 @@ export class VersionController {
|
|
|
848
848
|
}
|
|
849
849
|
}
|
|
850
850
|
|
|
851
|
+
updateVersionFrom43To44(): void {
|
|
852
|
+
const apcaExperimentEnabled =
|
|
853
|
+
Root.Runtime.experiments.getValueFromStorage('apca' as Root.ExperimentNames.ExperimentName);
|
|
854
|
+
if (apcaExperimentEnabled !== undefined) {
|
|
855
|
+
if (this.#settings.syncedStorage.has('apca')) {
|
|
856
|
+
return; // Already migrated
|
|
857
|
+
}
|
|
858
|
+
try {
|
|
859
|
+
const apcaSetting = this.#settings.moduleSetting('apca');
|
|
860
|
+
apcaSetting.set(apcaExperimentEnabled);
|
|
861
|
+
} catch {
|
|
862
|
+
// If the setting is not registered yet (e.g. in tests), skip.
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
851
867
|
/*
|
|
852
868
|
* Any new migration should be added before this comment.
|
|
853
869
|
*
|
|
@@ -816,7 +816,6 @@ export enum DevtoolsExperiments {
|
|
|
816
816
|
'protocol-monitor' = 13,
|
|
817
817
|
'sampling-heap-profiler-timeline' = 17,
|
|
818
818
|
'timeline-invalidation-tracking' = 26,
|
|
819
|
-
apca = 39,
|
|
820
819
|
'font-editor' = 41,
|
|
821
820
|
'instrumentation-breakpoints' = 61,
|
|
822
821
|
'use-source-map-scopes' = 76,
|
|
@@ -9,7 +9,6 @@ export enum ExperimentName {
|
|
|
9
9
|
PROTOCOL_MONITOR = 'protocol-monitor',
|
|
10
10
|
SAMPLING_HEAP_PROFILER_TIMELINE = 'sampling-heap-profiler-timeline',
|
|
11
11
|
TIMELINE_INVALIDATION_TRACKING = 'timeline-invalidation-tracking',
|
|
12
|
-
APCA = 'apca',
|
|
13
12
|
FONT_EDITOR = 'font-editor',
|
|
14
13
|
INSTRUMENTATION_BREAKPOINTS = 'instrumentation-breakpoints',
|
|
15
14
|
USE_SOURCE_MAP_SCOPES = 'use-source-map-scopes',
|
|
@@ -7,7 +7,6 @@ import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
|
|
|
7
7
|
import * as Protocol from '../../generated/protocol.js';
|
|
8
8
|
import * as Common from '../common/common.js';
|
|
9
9
|
import * as i18n from '../i18n/i18n.js';
|
|
10
|
-
import * as Root from '../root/root.js';
|
|
11
10
|
|
|
12
11
|
import type {CSSModel} from './CSSModel.js';
|
|
13
12
|
import {DebuggerModel, Events as DebuggerModelEvents} from './DebuggerModel.js';
|
|
@@ -534,9 +533,8 @@ export class OverlayModel extends SDKModel<EventTypes> implements ProtocolProxyA
|
|
|
534
533
|
gridHighlightConfig: {},
|
|
535
534
|
flexContainerHighlightConfig: {},
|
|
536
535
|
flexItemHighlightConfig: {},
|
|
537
|
-
contrastAlgorithm:
|
|
538
|
-
|
|
539
|
-
Protocol.Overlay.ContrastAlgorithm.Aa,
|
|
536
|
+
contrastAlgorithm: settings.moduleSetting('apca').get() ? Protocol.Overlay.ContrastAlgorithm.Apca :
|
|
537
|
+
Protocol.Overlay.ContrastAlgorithm.Aa,
|
|
540
538
|
};
|
|
541
539
|
|
|
542
540
|
if (mode === 'all' || mode === 'content') {
|
|
@@ -403,6 +403,10 @@ const UIStrings = {
|
|
|
403
403
|
* @description Title of a setting under the Console category in Settings
|
|
404
404
|
*/
|
|
405
405
|
logXmlhttprequests: 'Log XMLHttpRequests',
|
|
406
|
+
/**
|
|
407
|
+
* @description Title of a setting under the Elements category in Settings.
|
|
408
|
+
*/
|
|
409
|
+
apca: 'Advanced Perceptual Contrast Algorithm (APCA) replacing previous contrast ratio and AA/AAA guidelines',
|
|
406
410
|
} as const;
|
|
407
411
|
const str_ = i18n.i18n.registerUIStrings('core/sdk/sdk-meta.ts', UIStrings);
|
|
408
412
|
const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
|
|
@@ -521,6 +525,15 @@ Common.Settings.registerSettingExtension({
|
|
|
521
525
|
defaultValue: false,
|
|
522
526
|
});
|
|
523
527
|
|
|
528
|
+
Common.Settings.registerSettingExtension({
|
|
529
|
+
category: Common.Settings.SettingCategory.ELEMENTS,
|
|
530
|
+
storageType: Common.Settings.SettingStorageType.SYNCED,
|
|
531
|
+
title: i18nLazyString(UIStrings.apca),
|
|
532
|
+
settingName: 'apca',
|
|
533
|
+
settingType: Common.Settings.SettingType.BOOLEAN,
|
|
534
|
+
defaultValue: false,
|
|
535
|
+
});
|
|
536
|
+
|
|
524
537
|
Common.Settings.registerSettingExtension({
|
|
525
538
|
category: Common.Settings.SettingCategory.GRID,
|
|
526
539
|
storageType: Common.Settings.SettingStorageType.SYNCED,
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import '../../core/dom_extension/dom_extension.js';
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
7
|
+
// @ts-ignore: tsc 6.0 does not support side-effect imports without a type definition.
|
|
8
|
+
// We cannot use `@ts-expect-error` here because the import is correctly resolved
|
|
9
|
+
// when bundling the application (which doesn't error) and only errors in unbundled builds.
|
|
6
10
|
import '../../Images/Images.js';
|
|
7
11
|
|
|
8
12
|
if (window.opener) {
|
|
@@ -368,7 +368,6 @@ async function init(): Promise<void> {
|
|
|
368
368
|
safeRegisterExperiment(Root.ExperimentNames.ExperimentName.PROTOCOL_MONITOR, 'Protocol Monitor');
|
|
369
369
|
safeRegisterExperiment(
|
|
370
370
|
Root.ExperimentNames.ExperimentName.SAMPLING_HEAP_PROFILER_TIMELINE, 'Sampling heap profiler timeline');
|
|
371
|
-
safeRegisterExperiment(Root.ExperimentNames.ExperimentName.APCA, 'APCA');
|
|
372
371
|
|
|
373
372
|
const hostUnsyncedStorage: Common.Settings.SettingsBackingStore = {
|
|
374
373
|
register: (name: string) =>
|
|
@@ -254,7 +254,6 @@ async function init(): Promise<void> {
|
|
|
254
254
|
Root.Runtime.experiments.register(Root.ExperimentNames.ExperimentName.PROTOCOL_MONITOR, 'Protocol Monitor');
|
|
255
255
|
Root.Runtime.experiments.register(
|
|
256
256
|
Root.ExperimentNames.ExperimentName.SAMPLING_HEAP_PROFILER_TIMELINE, 'Sampling heap profiler timeline');
|
|
257
|
-
Root.Runtime.experiments.register(Root.ExperimentNames.ExperimentName.APCA, 'APCA');
|
|
258
257
|
|
|
259
258
|
const WINDOW_LOCAL_STORAGE: Common.Settings.SettingsBackingStore = {
|
|
260
259
|
register(_setting: string): void{},
|
|
@@ -372,12 +372,6 @@ export class MainImpl {
|
|
|
372
372
|
Root.Runtime.experiments.register(
|
|
373
373
|
Root.ExperimentNames.ExperimentName.USE_SOURCE_MAP_SCOPES, 'Use scope information from source maps');
|
|
374
374
|
|
|
375
|
-
// Advanced Perceptual Contrast Algorithm.
|
|
376
|
-
Root.Runtime.experiments.register(
|
|
377
|
-
Root.ExperimentNames.ExperimentName.APCA,
|
|
378
|
-
'Advanced Perceptual Contrast Algorithm (APCA) replacing previous contrast ratio and AA/AAA guidelines',
|
|
379
|
-
'https://developer.chrome.com/blog/new-in-devtools-89/#apca');
|
|
380
|
-
|
|
381
375
|
// Font Editor
|
|
382
376
|
Root.Runtime.experiments.register(
|
|
383
377
|
Root.ExperimentNames.ExperimentName.FONT_EDITOR, 'New font editor in the Styles tab',
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
6
|
+
// @ts-ignore: tsc 6.0 does not support side-effect imports without a type definition.
|
|
7
|
+
// We cannot use `@ts-expect-error` here because the import is correctly resolved
|
|
8
|
+
// when bundling the application (which doesn't error) and only errors in unbundled builds.
|
|
5
9
|
import '../../Images/Images.js';
|
|
6
10
|
import '../../core/dom_extension/dom_extension.js';
|
|
7
11
|
import '../../panels/sources/sources-meta.js';
|
|
@@ -6,6 +6,10 @@ import '../main/main-meta.js';
|
|
|
6
6
|
import '../inspector_main/inspector_main-meta.js';
|
|
7
7
|
import '../../core/sdk/sdk-meta.js';
|
|
8
8
|
import '../../models/workspace/workspace-meta.js';
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
10
|
+
// @ts-ignore: tsc 6.0 does not support side-effect imports without a type definition.
|
|
11
|
+
// We cannot use `@ts-expect-error` here because the import is correctly resolved
|
|
12
|
+
// when bundling the application (which doesn't error) and only errors in unbundled builds.
|
|
9
13
|
import '../../Images/Images.js';
|
|
10
14
|
import '../../models/logs/logs-meta.js';
|
|
11
15
|
import '../../models/persistence/persistence-meta.js';
|
|
@@ -1408,7 +1408,7 @@ inspectorBackend.registerCommand("Target.setDiscoverTargets", [{"name": "discove
|
|
|
1408
1408
|
inspectorBackend.registerCommand("Target.setRemoteLocations", [{"name": "locations", "type": "array", "optional": false, "description": "List of remote locations.", "typeRef": "Target.RemoteLocation"}], [], "Enables target discovery for the specified locations, when `setDiscoverTargets` was set to `true`.");
|
|
1409
1409
|
inspectorBackend.registerCommand("Target.getDevToolsTarget", [{"name": "targetId", "type": "string", "optional": false, "description": "Page or tab target ID.", "typeRef": "Target.TargetID"}], ["targetId"], "Gets the targetId of the DevTools page target opened for the given target (if any).");
|
|
1410
1410
|
inspectorBackend.registerCommand("Target.openDevTools", [{"name": "targetId", "type": "string", "optional": false, "description": "This can be the page or tab target ID.", "typeRef": "Target.TargetID"}, {"name": "panelId", "type": "string", "optional": true, "description": "The id of the panel we want DevTools to open initially. Currently supported panels are elements, console, network, sources, resources and performance.", "typeRef": null}], ["targetId"], "Opens a DevTools window for the target.");
|
|
1411
|
-
inspectorBackend.registerType("Target.TargetInfo", [{"name": "targetId", "type": "string", "optional": false, "description": "", "typeRef": "Target.TargetID"}, {"name": "type", "type": "string", "optional": false, "description": "List of types: https://source.chromium.org/chromium/chromium/src/+/main:content/browser/devtools/devtools_agent_host_impl.cc?ss=chromium&q=f:devtools%20-f:out%20%22::kTypeTab%5B%5D%22", "typeRef": null}, {"name": "title", "type": "string", "optional": false, "description": "", "typeRef": null}, {"name": "url", "type": "string", "optional": false, "description": "", "typeRef": null}, {"name": "attached", "type": "boolean", "optional": false, "description": "Whether the target has an attached client.", "typeRef": null}, {"name": "openerId", "type": "string", "optional": true, "description": "Opener target Id", "typeRef": "Target.TargetID"}, {"name": "canAccessOpener", "type": "boolean", "optional": false, "description": "Whether the target has access to the originating window.", "typeRef": null}, {"name": "openerFrameId", "type": "string", "optional": true, "description": "Frame id of originating window (is only set if target has an opener).", "typeRef": "Page.FrameId"}, {"name": "parentFrameId", "type": "string", "optional": true, "description": "Id of the parent frame,
|
|
1411
|
+
inspectorBackend.registerType("Target.TargetInfo", [{"name": "targetId", "type": "string", "optional": false, "description": "", "typeRef": "Target.TargetID"}, {"name": "type", "type": "string", "optional": false, "description": "List of types: https://source.chromium.org/chromium/chromium/src/+/main:content/browser/devtools/devtools_agent_host_impl.cc?ss=chromium&q=f:devtools%20-f:out%20%22::kTypeTab%5B%5D%22", "typeRef": null}, {"name": "title", "type": "string", "optional": false, "description": "", "typeRef": null}, {"name": "url", "type": "string", "optional": false, "description": "", "typeRef": null}, {"name": "attached", "type": "boolean", "optional": false, "description": "Whether the target has an attached client.", "typeRef": null}, {"name": "openerId", "type": "string", "optional": true, "description": "Opener target Id", "typeRef": "Target.TargetID"}, {"name": "canAccessOpener", "type": "boolean", "optional": false, "description": "Whether the target has access to the originating window.", "typeRef": null}, {"name": "openerFrameId", "type": "string", "optional": true, "description": "Frame id of originating window (is only set if target has an opener).", "typeRef": "Page.FrameId"}, {"name": "parentFrameId", "type": "string", "optional": true, "description": "Id of the parent frame, present for \\\"iframe\\\" and \\\"worker\\\" targets. For nested workers, this is the \\\"ancestor\\\" frame that created the first worker in the nested chain.", "typeRef": "Page.FrameId"}, {"name": "browserContextId", "type": "string", "optional": true, "description": "", "typeRef": "Browser.BrowserContextID"}, {"name": "subtype", "type": "string", "optional": true, "description": "Provides additional details for specific target types. For example, for the type of \\\"page\\\", this may be set to \\\"prerender\\\".", "typeRef": null}]);
|
|
1412
1412
|
inspectorBackend.registerType("Target.FilterEntry", [{"name": "exclude", "type": "boolean", "optional": true, "description": "If set, causes exclusion of matching targets from the list.", "typeRef": null}, {"name": "type", "type": "string", "optional": true, "description": "If not present, matches any type.", "typeRef": null}]);
|
|
1413
1413
|
inspectorBackend.registerType("Target.TargetFilter", [{"name": "TargetFilter", "type": "array", "optional": false, "description": "The entries in TargetFilter are matched sequentially against targets and the first entry that matches determines if the target is included or not, depending on the value of `exclude` field in the entry. If filter is not specified, the one assumed is [{type: \\\"browser\\\", exclude: true}, {type: \\\"tab\\\", exclude: true}, {}] (i.e. include everything but `browser` and `tab`).", "typeRef": "Target.FilterEntry"}]);
|
|
1414
1414
|
inspectorBackend.registerType("Target.RemoteLocation", [{"name": "host", "type": "string", "optional": false, "description": "", "typeRef": null}, {"name": "port", "type": "number", "optional": false, "description": "", "typeRef": null}]);
|
|
@@ -1489,7 +1489,7 @@ inspectorBackend.registerType("WebAuthn.VirtualAuthenticatorOptions", [{"name":
|
|
|
1489
1489
|
inspectorBackend.registerType("WebAuthn.Credential", [{"name": "credentialId", "type": "string", "optional": false, "description": "", "typeRef": null}, {"name": "isResidentCredential", "type": "boolean", "optional": false, "description": "", "typeRef": null}, {"name": "rpId", "type": "string", "optional": true, "description": "Relying Party ID the credential is scoped to. Must be set when adding a credential.", "typeRef": null}, {"name": "privateKey", "type": "string", "optional": false, "description": "The ECDSA P-256 private key in PKCS#8 format.", "typeRef": null}, {"name": "userHandle", "type": "string", "optional": true, "description": "An opaque byte sequence with a maximum size of 64 bytes mapping the credential to a specific user.", "typeRef": null}, {"name": "signCount", "type": "number", "optional": false, "description": "Signature counter. This is incremented by one for each successful assertion. See https://w3c.github.io/webauthn/#signature-counter", "typeRef": null}, {"name": "largeBlob", "type": "string", "optional": true, "description": "The large blob associated with the credential. See https://w3c.github.io/webauthn/#sctn-large-blob-extension", "typeRef": null}, {"name": "backupEligibility", "type": "boolean", "optional": true, "description": "Assertions returned by this credential will have the backup eligibility (BE) flag set to this value. Defaults to the authenticator's defaultBackupEligibility value.", "typeRef": null}, {"name": "backupState", "type": "boolean", "optional": true, "description": "Assertions returned by this credential will have the backup state (BS) flag set to this value. Defaults to the authenticator's defaultBackupState value.", "typeRef": null}, {"name": "userName", "type": "string", "optional": true, "description": "The credential's user.name property. Equivalent to empty if not set. https://w3c.github.io/webauthn/#dom-publickeycredentialentity-name", "typeRef": null}, {"name": "userDisplayName", "type": "string", "optional": true, "description": "The credential's user.displayName property. Equivalent to empty if not set. https://w3c.github.io/webauthn/#dom-publickeycredentialuserentity-displayname", "typeRef": null}]);
|
|
1490
1490
|
|
|
1491
1491
|
// WebMCP.
|
|
1492
|
-
inspectorBackend.registerEnum("WebMCP.InvocationStatus", {
|
|
1492
|
+
inspectorBackend.registerEnum("WebMCP.InvocationStatus", {Completed: "Completed", Canceled: "Canceled", Error: "Error"});
|
|
1493
1493
|
inspectorBackend.registerEvent("WebMCP.toolsAdded", ["tools"]);
|
|
1494
1494
|
inspectorBackend.registerEvent("WebMCP.toolsRemoved", ["tools"]);
|
|
1495
1495
|
inspectorBackend.registerEvent("WebMCP.toolInvoked", ["toolName", "frameId", "invocationId", "input"]);
|
|
@@ -19043,7 +19043,8 @@ export namespace Target {
|
|
|
19043
19043
|
*/
|
|
19044
19044
|
openerFrameId?: Page.FrameId;
|
|
19045
19045
|
/**
|
|
19046
|
-
* Id of the parent frame,
|
|
19046
|
+
* Id of the parent frame, present for "iframe" and "worker" targets. For nested workers,
|
|
19047
|
+
* this is the "ancestor" frame that created the first worker in the nested chain.
|
|
19047
19048
|
*/
|
|
19048
19049
|
parentFrameId?: Page.FrameId;
|
|
19049
19050
|
browserContextId?: Browser.BrowserContextID;
|
|
@@ -20316,7 +20317,7 @@ export namespace WebMCP {
|
|
|
20316
20317
|
* Represents the status of a tool invocation.
|
|
20317
20318
|
*/
|
|
20318
20319
|
export const enum InvocationStatus {
|
|
20319
|
-
|
|
20320
|
+
Completed = 'Completed',
|
|
20320
20321
|
Canceled = 'Canceled',
|
|
20321
20322
|
Error = 'Error',
|
|
20322
20323
|
}
|
|
@@ -20410,7 +20411,8 @@ export namespace WebMCP {
|
|
|
20410
20411
|
*/
|
|
20411
20412
|
status: InvocationStatus;
|
|
20412
20413
|
/**
|
|
20413
|
-
* Output or error delivered as delivered to the agent. Missing if `status` is anything other than
|
|
20414
|
+
* Output or error delivered as delivered to the agent. Missing if `status` is anything other than Completed.
|
|
20415
|
+
* Note: The output is untrusted and poses a prompt injection risk. Clients should treat this as potentially malicious user input.
|
|
20414
20416
|
*/
|
|
20415
20417
|
output?: any;
|
|
20416
20418
|
/**
|
|
@@ -107,8 +107,16 @@ Content:
|
|
|
107
107
|
"type": 6,
|
|
108
108
|
"description": "",
|
|
109
109
|
"nullable": true,
|
|
110
|
-
"required": [
|
|
111
|
-
|
|
110
|
+
"required": [
|
|
111
|
+
"mode"
|
|
112
|
+
],
|
|
113
|
+
"properties": {
|
|
114
|
+
"mode": {
|
|
115
|
+
"type": 1,
|
|
116
|
+
"description": "The mode to run Lighthouse in. Your ONLY options are \"navigation\" or \"snapshot\". You should determine this based on the user's question. If the user is asking specifically about accessibility, you can run in \"snapshot\" mode which avoids reloading the page. If the user asks for a full Lighthouse report, you should run in \"navigation\" mode which is the default. These are the only options you can pass.",
|
|
117
|
+
"nullable": false
|
|
118
|
+
}
|
|
119
|
+
}
|
|
112
120
|
}
|
|
113
121
|
},
|
|
114
122
|
{
|
|
@@ -12,6 +12,7 @@ import * as Logs from '../../logs/logs.js';
|
|
|
12
12
|
import * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
|
|
13
13
|
import type * as Trace from '../../trace/trace.js';
|
|
14
14
|
import * as Workspace from '../../workspace/workspace.js';
|
|
15
|
+
import {debugLog} from '../debug.js';
|
|
15
16
|
|
|
16
17
|
import {AccessibilityContext} from './AccessibilityAgent.js';
|
|
17
18
|
import {
|
|
@@ -306,29 +307,44 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
306
307
|
}
|
|
307
308
|
});
|
|
308
309
|
|
|
309
|
-
|
|
310
|
+
type LHSupportedRunMode = Extract<LHModel.RunTypes.RunMode, 'navigation'|'snapshot'>;
|
|
311
|
+
const parseLighthouseMode = (mode?: string): LHSupportedRunMode => {
|
|
312
|
+
return mode === 'snapshot' ? 'snapshot' : 'navigation';
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
this.declareFunction<{mode: LHSupportedRunMode}>('runLighthouseAudits', {
|
|
310
316
|
description:
|
|
311
317
|
'Records a Lighthouse audit on the current page. Use this to debug accessibility, SEO, and best practices. (For performance metrics like LCP, use performanceRecordAndReload instead).',
|
|
312
318
|
parameters: {
|
|
313
319
|
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
314
320
|
description: '',
|
|
315
321
|
nullable: true,
|
|
316
|
-
required: [],
|
|
317
|
-
properties: {
|
|
322
|
+
required: ['mode'],
|
|
323
|
+
properties: {
|
|
324
|
+
mode: {
|
|
325
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
326
|
+
description:
|
|
327
|
+
'The mode to run Lighthouse in. Your ONLY options are "navigation" or "snapshot". You should determine this based on the user\'s question. If the user is asking specifically about accessibility, you can run in "snapshot" mode which avoids reloading the page. If the user asks for a full Lighthouse report, you should run in "navigation" mode which is the default. These are the only options you can pass.',
|
|
328
|
+
nullable: false,
|
|
329
|
+
}
|
|
330
|
+
},
|
|
318
331
|
},
|
|
319
|
-
displayInfoFromArgs:
|
|
332
|
+
displayInfoFromArgs: args => {
|
|
333
|
+
const mode = parseLighthouseMode(args.mode);
|
|
320
334
|
return {
|
|
321
335
|
title: 'Auditing your page with Lighthouse',
|
|
322
|
-
action:
|
|
336
|
+
action: `runLighthouseAudits(${mode})`,
|
|
323
337
|
};
|
|
324
338
|
},
|
|
325
|
-
handler: async
|
|
339
|
+
handler: async params => {
|
|
326
340
|
if (!this.#lighthouseRecording) {
|
|
327
341
|
return {
|
|
328
342
|
error: 'Lighthouse report is not available.',
|
|
329
343
|
};
|
|
330
344
|
}
|
|
331
|
-
const
|
|
345
|
+
const mode = parseLighthouseMode(params.mode);
|
|
346
|
+
debugLog(`Recording with Lighthouse; runMode=${mode}`);
|
|
347
|
+
const result = await this.#lighthouseRecording({mode});
|
|
332
348
|
if (!result) {
|
|
333
349
|
return {error: 'Failed to generate Lighthouse report.'};
|
|
334
350
|
}
|
|
@@ -49,6 +49,13 @@ const UIStringsNotTranslated = {
|
|
|
49
49
|
} as const;
|
|
50
50
|
const lockedString = i18n.i18n.lockedString;
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Labels used to identify specific periods or categories in the trace for getting main thread summary.
|
|
54
|
+
* Supports hardcoded phases, dynamic navigation IDs (`NAVIGATION_X`), and insight models.
|
|
55
|
+
*/
|
|
56
|
+
type MainThreadSectionLabel = 'nav-to-lcp'|'lcp-ttfb'|'lcp-render-delay'|'trace-bounds'|'NO_NAVIGATION'|
|
|
57
|
+
`NAVIGATION_${string}`|keyof Trace.Insights.Types.InsightModels;
|
|
58
|
+
|
|
52
59
|
/**
|
|
53
60
|
* WARNING: preamble defined in code is only used when userTier is
|
|
54
61
|
* TESTERS. Otherwise, a server-side preamble is used (see
|
|
@@ -102,7 +109,8 @@ You can also use this key with \`selectEventByKey\` to show the user a specific
|
|
|
102
109
|
|
|
103
110
|
## Step-by-step instructions for debugging performance issues
|
|
104
111
|
|
|
105
|
-
Note: if the user asks a specific question about the trace (such as "What is my LCP?", or "How many requests were render-blocking?", directly answer their question
|
|
112
|
+
Note: if the user asks a specific question about the trace (such as "What is my LCP?", or "How many requests were render-blocking?"), directly answer their question using available data. However, if the user asks a general question like "What performance issues exist?" or requests an investigation, you MUST NOT give a generic answer. You must treat it as a full performance investigation (Step 1) and call main thread functions to find specific issues. Generic advice like "reduce long tasks" without specific details is UNACCEPTABLE.
|
|
113
|
+
|
|
106
114
|
|
|
107
115
|
### Step 1: Determine a performance problem to investigate
|
|
108
116
|
|
|
@@ -138,11 +146,22 @@ Note: if the user asks a specific question about the trace (such as "What is my
|
|
|
138
146
|
|
|
139
147
|
## Guidelines
|
|
140
148
|
|
|
149
|
+
- You must call \`getMainThreadTrackSummary\` (by specifying a time range) or \`getMainThreadTrackSummaryByLabel\` (with the relevant label) to investigate the main thread activity before giving the user a reply or suggesting solutions for any performance problem or insight. Call \`getMainThreadTrackSummary\` with specific bounds when you identify a specific time range of interest from the initial data. This applies even if you already have some information about that period from \`getInsightDetails\` or the initial trace summary.
|
|
150
|
+
- Dig Deeper: Before replying, you should really dig into the main thread activity to uncover what the performance issues actually are. Use the initially provided main thread data as a reference to identify interesting tasks or time ranges, and then use those time bounds to call functions like \`getMainThreadTrackSummary\` to get more detailed data. Do not solely rely on the information from the initial data; ensure you identify the root cause before suggesting solutions.
|
|
151
|
+
- No Shortcutting: Even if the initial facts contain specific line numbers or function names, you are not allowed to reply using only that information. You MUST call \`getMainThreadTrackSummary\` with the time bounds of the task to inspect its full context and children before describing it to the user.
|
|
152
|
+
- Look for Aggregated Cost: Performance issues are not always caused by a single "Long Task". Many small, frequent events (like unthrottled \`mousemove\` or \`scroll\` handlers) can add up to significant main thread blockage. Use the Bottom-Up summary in \`getMainThreadTrackSummary\` to identify functions with high total time, even if they are not associated with a Long Task.
|
|
141
153
|
- Use the provided functions to get detailed performance data. Prioritize functions that provide context relevant to the performance issue being investigated.
|
|
142
154
|
- Before finalizing your advice, look over it and validate using any relevant functions. If something seems off, refine the advice before giving it to the user.
|
|
143
155
|
- Base your analysis and advice solely on the data retrieved through the provided functions. Always use the provided functions to gather sufficient data when needed.
|
|
144
156
|
- Use absolute microsecond timestamps for any function that requires a \`min\` and \`max\` bounds. These timestamps can be found in the trace summary or within the details of an insight.
|
|
145
157
|
- Example: If the trace bounds are {min: 1000, max: 5000} and you want to investigate a specific interaction that happened between 2000 and 3000, you should call \`getMainThreadTrackSummary({min: 2000, max: 3000})\`.
|
|
158
|
+
- Available labels for \`getMainThreadTrackSummaryByLabel\` include:
|
|
159
|
+
- \`trace-bounds\` (entire trace)
|
|
160
|
+
- \`nav-to-lcp\` (navigation to LCP)
|
|
161
|
+
- \`lcp-ttfb\` (LCP TTFB phase)
|
|
162
|
+
- \`lcp-render-delay\` (LCP render delay phase)
|
|
163
|
+
- Insight names: \`LCPBreakdown\`, \`CLSCulprits\`, \`RenderBlocking\`, \`NetworkDependencyTree\`, \`ImageDelivery\`, \`FontDisplay\`, \`ThirdParties\`, \`ForcedReflow\`, \`Cache\`, \`DOMSize\`
|
|
164
|
+
- Navigation IDs: \`NAVIGATION_0\`, \`NAVIGATION_1\`, etc.
|
|
146
165
|
- Use \`getEventByKey\` to get data on a specific trace event. This is great for root-cause analysis or validating any assumptions.
|
|
147
166
|
- Provide clear, actionable recommendations. Avoid technical jargon unless necessary, and explain any technical terms used.
|
|
148
167
|
- If you see a generic task like "Task", "Evaluate script" or "(anonymous)" in the main thread activity, try to look at its children to see what actual functions are executed and refer to those. When referencing the main thread activity, be as specific as you can. Ensure you identify to the user relevant functions and which script they were defined in. Avoid referencing "Task", "Evaluate script" and "(anonymous)" nodes if possible and instead focus on their children.
|
|
@@ -777,6 +796,52 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
777
796
|
this.#functionCallCacheForFocus.set(focus, cache);
|
|
778
797
|
}
|
|
779
798
|
|
|
799
|
+
async #handleMainThreadTrackSummary(
|
|
800
|
+
bounds: Trace.Types.Timing.TraceWindowMicro,
|
|
801
|
+
focus: AgentFocus,
|
|
802
|
+
functionName: string,
|
|
803
|
+
cacheKey: string,
|
|
804
|
+
): Promise<FunctionCallHandlerResult<{summary: string}>> {
|
|
805
|
+
const formatter = this.#formatter;
|
|
806
|
+
if (!formatter) {
|
|
807
|
+
throw new Error('missing formatter');
|
|
808
|
+
}
|
|
809
|
+
const summary = await formatter.formatMainThreadTrackSummary(bounds);
|
|
810
|
+
if (this.#isFunctionResponseTooLarge(summary)) {
|
|
811
|
+
return {
|
|
812
|
+
error:
|
|
813
|
+
`${functionName} response is too large. Try investigating using other functions, or a more narrow bounds`,
|
|
814
|
+
};
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
const byteCount = Platform.StringUtilities.countWtf8Bytes(summary);
|
|
818
|
+
Host.userMetrics.performanceAIMainThreadActivityResponseSize(byteCount);
|
|
819
|
+
|
|
820
|
+
this.#cacheFunctionResult(focus, cacheKey, summary);
|
|
821
|
+
const widgets: AiWidget[] = [];
|
|
822
|
+
widgets.push({
|
|
823
|
+
name: 'TIMELINE_RANGE_SUMMARY',
|
|
824
|
+
data: {
|
|
825
|
+
parsedTrace: focus.parsedTrace,
|
|
826
|
+
bounds,
|
|
827
|
+
track: 'main',
|
|
828
|
+
},
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
widgets.push({
|
|
832
|
+
name: 'BOTTOM_UP_TREE',
|
|
833
|
+
data: {
|
|
834
|
+
bounds,
|
|
835
|
+
parsedTrace: focus.parsedTrace,
|
|
836
|
+
},
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
return {
|
|
840
|
+
result: {summary},
|
|
841
|
+
widgets,
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
|
|
780
845
|
#declareFunctions(context: PerformanceTraceContext): void {
|
|
781
846
|
const focus = context.getItem();
|
|
782
847
|
const {parsedTrace} = focus;
|
|
@@ -972,53 +1037,51 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
972
1037
|
handler: async args => {
|
|
973
1038
|
debugLog('Function call: getMainThreadTrackSummary');
|
|
974
1039
|
|
|
975
|
-
if (!this.#formatter) {
|
|
976
|
-
throw new Error('missing formatter');
|
|
977
|
-
}
|
|
978
|
-
|
|
979
1040
|
const bounds = createBounds(args.min, args.max);
|
|
980
1041
|
if (!bounds) {
|
|
981
1042
|
return {error: 'invalid bounds'};
|
|
982
1043
|
}
|
|
983
1044
|
|
|
984
|
-
const formatter = this.#formatter;
|
|
985
|
-
const summary = await formatter.formatMainThreadTrackSummary(bounds);
|
|
986
|
-
if (this.#isFunctionResponseTooLarge(summary)) {
|
|
987
|
-
return {
|
|
988
|
-
error:
|
|
989
|
-
'getMainThreadTrackSummary response is too large. Try investigating using other functions, or a more narrow bounds',
|
|
990
|
-
};
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
const byteCount = Platform.StringUtilities.countWtf8Bytes(summary);
|
|
994
|
-
Host.userMetrics.performanceAIMainThreadActivityResponseSize(byteCount);
|
|
995
|
-
|
|
996
1045
|
const key = `getMainThreadTrackSummary({min: ${bounds.min}, max: ${bounds.max}})`;
|
|
997
|
-
this.#
|
|
998
|
-
|
|
999
|
-
widgets.push({
|
|
1000
|
-
name: 'TIMELINE_RANGE_SUMMARY',
|
|
1001
|
-
data: {
|
|
1002
|
-
parsedTrace,
|
|
1003
|
-
bounds,
|
|
1004
|
-
track: 'main',
|
|
1005
|
-
},
|
|
1006
|
-
});
|
|
1046
|
+
return await this.#handleMainThreadTrackSummary(bounds, focus, 'getMainThreadTrackSummary', key);
|
|
1047
|
+
},
|
|
1007
1048
|
|
|
1008
|
-
|
|
1009
|
-
name: 'BOTTOM_UP_TREE',
|
|
1010
|
-
data: {
|
|
1011
|
-
bounds,
|
|
1012
|
-
parsedTrace,
|
|
1013
|
-
},
|
|
1014
|
-
});
|
|
1049
|
+
});
|
|
1015
1050
|
|
|
1051
|
+
this.declareFunction<{label: MainThreadSectionLabel}, {summary: string}>('getMainThreadTrackSummaryByLabel', {
|
|
1052
|
+
description:
|
|
1053
|
+
'Returns a focused, detailed summary of the main thread for a predefined labeled period. Use this to get more relevant detail than the initial trace summary before diagnosing issues.',
|
|
1054
|
+
parameters: {
|
|
1055
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
1056
|
+
description: '',
|
|
1057
|
+
nullable: false,
|
|
1058
|
+
properties: {
|
|
1059
|
+
label: {
|
|
1060
|
+
type: Host.AidaClient.ParametersTypes.STRING,
|
|
1061
|
+
description:
|
|
1062
|
+
'The label of the period to investigate (e.g., \'LCPBreakdown\', \'CLSCulprits\', \'nav-to-lcp\').',
|
|
1063
|
+
nullable: false,
|
|
1064
|
+
},
|
|
1065
|
+
},
|
|
1066
|
+
required: ['label']
|
|
1067
|
+
},
|
|
1068
|
+
displayInfoFromArgs: args => {
|
|
1016
1069
|
return {
|
|
1017
|
-
|
|
1018
|
-
|
|
1070
|
+
title: lockedString(UIStringsNotTranslated.mainThreadActivity),
|
|
1071
|
+
action: `getMainThreadTrackSummaryByLabel('${args.label}')`
|
|
1019
1072
|
};
|
|
1020
1073
|
},
|
|
1074
|
+
handler: async args => {
|
|
1075
|
+
debugLog('Function call: getMainThreadTrackSummaryByLabel');
|
|
1076
|
+
|
|
1077
|
+
const bounds = this.#getBoundsForLabel(args.label, focus);
|
|
1078
|
+
if (!bounds) {
|
|
1079
|
+
return {error: `Invalid label: ${args.label}`};
|
|
1080
|
+
}
|
|
1021
1081
|
|
|
1082
|
+
const key = `getMainThreadTrackSummaryByLabel('${args.label}')`;
|
|
1083
|
+
return await this.#handleMainThreadTrackSummary(bounds, focus, 'getMainThreadTrackSummaryByLabel', key);
|
|
1084
|
+
},
|
|
1022
1085
|
});
|
|
1023
1086
|
|
|
1024
1087
|
this.declareFunction<
|
|
@@ -1362,6 +1425,68 @@ export class PerformanceAgent extends AiAgent<AgentFocus> {
|
|
|
1362
1425
|
}
|
|
1363
1426
|
}
|
|
1364
1427
|
|
|
1428
|
+
#getBoundsForLabel(label: MainThreadSectionLabel, focus: AgentFocus): Trace.Types.Timing.TraceWindowMicro|null {
|
|
1429
|
+
const {parsedTrace} = focus;
|
|
1430
|
+
const insightSet = focus.primaryInsightSet;
|
|
1431
|
+
|
|
1432
|
+
if (label === 'nav-to-lcp') {
|
|
1433
|
+
if (insightSet) {
|
|
1434
|
+
const lcp = Trace.Insights.Common.getLCP(insightSet);
|
|
1435
|
+
if (lcp) {
|
|
1436
|
+
return Trace.Helpers.Timing.traceWindowFromMicroSeconds(
|
|
1437
|
+
insightSet.bounds.min, lcp.event.ts as Trace.Types.Timing.Micro);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
return null;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
if (label === 'lcp-ttfb') {
|
|
1444
|
+
if (insightSet) {
|
|
1445
|
+
const subparts = insightSet.model.LCPBreakdown?.subparts;
|
|
1446
|
+
if (subparts?.ttfb) {
|
|
1447
|
+
return subparts.ttfb;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
return null;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
if (label === 'lcp-render-delay') {
|
|
1454
|
+
if (insightSet) {
|
|
1455
|
+
const subparts = insightSet.model.LCPBreakdown?.subparts;
|
|
1456
|
+
if (subparts?.renderDelay) {
|
|
1457
|
+
return subparts.renderDelay;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
return null;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
if (label === 'trace-bounds') {
|
|
1464
|
+
return parsedTrace.data.Meta.traceBounds;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
for (const is of parsedTrace.insights?.values() ?? []) {
|
|
1468
|
+
if (is.id === label) {
|
|
1469
|
+
return is.bounds;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
if (insightSet) {
|
|
1474
|
+
const model = insightSet.model[label as keyof Trace.Insights.Types.InsightModels];
|
|
1475
|
+
if (model) {
|
|
1476
|
+
return Trace.Insights.Common.insightBounds(model, insightSet.bounds);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
for (const is of parsedTrace.insights?.values() ?? []) {
|
|
1481
|
+
const model = is.model[label as keyof Trace.Insights.Types.InsightModels];
|
|
1482
|
+
if (model) {
|
|
1483
|
+
return Trace.Insights.Common.insightBounds(model, is.bounds);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
return null;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1365
1490
|
async addElementAnnotation(elementId: string, annotationMessage: string):
|
|
1366
1491
|
Promise<FunctionCallHandlerResult<unknown>> {
|
|
1367
1492
|
if (!Annotations.AnnotationRepository.annotationsEnabled()) {
|