chrome-devtools-frontend 1.0.1696961 → 1.0.1697998
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/.geminiignore +0 -1
- package/.stylelintignore +2 -0
- package/front_end/core/common/Color.ts +5 -2
- package/front_end/core/common/VersionController.ts +5 -1
- package/front_end/core/host/InspectorFrontendHostAPI.ts +16 -3
- package/front_end/core/host/InspectorFrontendHostStub.ts +3 -2
- package/front_end/core/host/ResourceLoader.ts +1 -2
- package/front_end/core/platform/api/HostRuntime.ts +1 -0
- package/front_end/core/platform/browser/HostRuntime.ts +4 -0
- package/front_end/core/platform/node/HostRuntime.ts +5 -0
- package/front_end/core/root/Runtime.ts +5 -0
- package/front_end/core/sdk/AnimationModel.ts +9 -1
- package/front_end/core/sdk/DOMModel.ts +13 -0
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +9 -6
- package/front_end/core/sdk/SourceMapScopesInfo.ts +3 -1
- package/front_end/foundation/Universe.ts +8 -0
- package/front_end/generated/InspectorBackendCommands.ts +4 -1
- package/front_end/generated/protocol-mapping.d.ts +19 -0
- package/front_end/generated/protocol-proxy-api.d.ts +15 -0
- package/front_end/generated/protocol.ts +43 -2
- package/front_end/models/ai_assistance/AiAgent2.ts +20 -18
- package/front_end/models/ai_assistance/AiConversation.ts +38 -12
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +9 -2
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +26 -0
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +13 -4
- package/front_end/models/ai_assistance/ai_assistance.ts +4 -4
- package/front_end/models/ai_assistance/skills/performance.md +4 -3
- package/front_end/models/ai_assistance/tools/CookieUtils.ts +10 -8
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +1 -1
- package/front_end/models/ai_assistance/tools/GetElementAccessibilityDetails.ts +1 -3
- package/front_end/models/ai_assistance/tools/GetNetworkRequestDetails.ts +9 -8
- package/front_end/models/ai_assistance/tools/GetSourceContent.ts +5 -6
- package/front_end/models/ai_assistance/tools/GetStorageValues.ts +6 -25
- package/front_end/models/ai_assistance/tools/GetStyles.ts +1 -3
- package/front_end/models/ai_assistance/tools/{GetFunctionCode.ts → GetTraceFunctionCode.ts} +26 -13
- package/front_end/models/ai_assistance/tools/{GetResourceContent.ts → GetTraceResourceContent.ts} +31 -11
- package/front_end/models/ai_assistance/tools/ListNetworkRequests.ts +7 -6
- package/front_end/models/ai_assistance/tools/ListPageOrigins.ts +8 -5
- package/front_end/models/ai_assistance/tools/ListSources.ts +8 -10
- package/front_end/models/ai_assistance/tools/ListStorageKeys.ts +6 -25
- package/front_end/models/ai_assistance/tools/README.md +5 -3
- package/front_end/models/ai_assistance/tools/ResolveDevtoolsNodePath.ts +1 -2
- package/front_end/models/ai_assistance/tools/Tool.ts +54 -16
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +6 -6
- package/front_end/models/change_tracker/ChangeTracker.ts +89 -0
- package/front_end/models/change_tracker/change_tracker.ts +9 -0
- package/front_end/models/elements/DOMChanges.ts +238 -0
- package/front_end/models/elements/elements.ts +2 -0
- package/front_end/models/issues_manager/MarkdownIssueDescription.ts +2 -2
- package/front_end/models/live-metrics/LiveMetrics.ts +1 -2
- package/front_end/models/trace/ModelImpl.ts +0 -6
- package/front_end/models/trace/Processor.ts +4 -7
- package/front_end/models/trace/helpers/Timing.ts +2 -1
- package/front_end/models/trace/types/Overlays.ts +12 -1
- package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +67 -19
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +3 -1
- package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +25 -5
- package/front_end/panels/application/IndexedDBViews.ts +1 -1
- package/front_end/panels/browser_debugger/ObjectEventListenersSidebarPane.ts +2 -3
- package/front_end/panels/elements/DOMTreeContextMenu.ts +16 -23
- package/front_end/panels/elements/ElementsTreeElement.ts +384 -79
- package/front_end/panels/elements/ElementsTreeOutline.ts +541 -82
- package/front_end/panels/elements/EventListenersWidget.ts +0 -1
- package/front_end/panels/event_listeners/EventListenersView.ts +241 -297
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +1 -1
- package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -2
- package/front_end/panels/network/NetworkConfigView.ts +141 -116
- package/front_end/panels/network/NetworkPanel.ts +140 -52
- package/front_end/panels/network/RequestHeadersView.ts +65 -32
- package/front_end/panels/network/components/RequestHeadersView.css +7 -1
- package/front_end/panels/network/forward/BackendLinking.ts +52 -0
- package/front_end/panels/network/forward/forward.ts +2 -0
- package/front_end/panels/settings/BackendLinkingSettingsTab.ts +308 -0
- package/front_end/panels/settings/backendLinkingSettingsTab.css +78 -0
- package/front_end/panels/settings/settings-meta.ts +25 -0
- package/front_end/panels/settings/settings.ts +2 -0
- package/front_end/panels/timeline/README.md +3 -2
- package/front_end/panels/timeline/TimelineFlameChartView.ts +23 -2
- package/front_end/panels/timeline/TimelineTreeView.ts +11 -1
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +64 -4
- package/front_end/panels/timeline/timelineFlameChartView.css +47 -0
- package/front_end/panels/whats_new/ReleaseNoteText.ts +8 -8
- package/front_end/panels/whats_new/resources/WNDT.md +6 -6
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +6 -0
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +5 -8
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Coverage.d.ts +6 -0
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Coverage.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Coverage.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.js +1 -5
- package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/ScreenRecording.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/types.d.ts +6 -0
- package/front_end/third_party/puppeteer/package/package.json +2 -2
- package/front_end/third_party/puppeteer/package/src/cdp/Coverage.ts +6 -0
- package/front_end/third_party/puppeteer/package/src/cdp/ScreenRecording.ts +3 -7
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/third_party/web-vitals/README.chromium +2 -2
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +8 -5
- package/front_end/third_party/web-vitals/package/package.json +1 -1
- package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +8 -4
- package/front_end/third_party/web-vitals/rebuild.sh +2 -2
- package/front_end/ui/comments/CommentOverlayManager.ts +169 -40
- package/front_end/ui/comments/CommentThreadWidget.ts +221 -0
- package/front_end/ui/comments/CommentsOverlayWidget.ts +124 -12
- package/front_end/ui/comments/commentThreadWidget.css +173 -0
- package/front_end/ui/comments/comments.ts +2 -0
- package/front_end/ui/comments/commentsOverlay.css +6 -0
- package/front_end/ui/legacy/ContextMenu.ts +19 -0
- package/front_end/ui/legacy/SoftContextMenu.ts +6 -0
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +66 -22
- package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
- package/package.json +9 -8
|
@@ -38,7 +38,7 @@ import {FileContext} from './contexts/FileContext.js';
|
|
|
38
38
|
import {PerformanceTraceContext} from './contexts/PerformanceTraceContext.js';
|
|
39
39
|
import {RequestContext} from './contexts/RequestContext.js';
|
|
40
40
|
import {StorageContext} from './contexts/StorageContext.js';
|
|
41
|
-
import {ToolAnnotation} from './tools/Tool.js';
|
|
41
|
+
import {type OriginLockState, ToolAnnotation} from './tools/Tool.js';
|
|
42
42
|
import {ToolRegistry} from './tools/ToolRegistry.js';
|
|
43
43
|
|
|
44
44
|
export const NOT_FOUND_IMAGE_DATA = '';
|
|
@@ -381,7 +381,7 @@ export class AiConversation {
|
|
|
381
381
|
const isTransitioningFromStorage = previousType === ConversationType.STORAGE && type !== ConversationType.STORAGE;
|
|
382
382
|
const history = isTransitioningFromStorage ? [] : this.#filterHistoryForNewAgent();
|
|
383
383
|
|
|
384
|
-
const
|
|
384
|
+
const baseOptions = {
|
|
385
385
|
aidaClient: this.#aidaClient,
|
|
386
386
|
serverSideLoggingAllowed: isAiAssistanceServerSideLoggingAllowed(),
|
|
387
387
|
sessionId: this.id,
|
|
@@ -390,13 +390,18 @@ export class AiConversation {
|
|
|
390
390
|
onInspectElement: this.#onInspectElement,
|
|
391
391
|
networkTimeCalculator: this.#networkTimeCalculator,
|
|
392
392
|
lighthouseRecording: this.#lighthouseRecording,
|
|
393
|
-
allowedOrigin: this.allowedOrigin,
|
|
394
393
|
history,
|
|
395
394
|
targetManager: this.#targetManager,
|
|
396
395
|
};
|
|
397
396
|
|
|
398
|
-
this.#agent = Root.Runtime.hostConfig.devToolsAiV2Architecture?.enabled ? new AiAgent2(
|
|
399
|
-
|
|
397
|
+
this.#agent = Root.Runtime.hostConfig.devToolsAiV2Architecture?.enabled ? new AiAgent2({
|
|
398
|
+
...baseOptions,
|
|
399
|
+
originLock: this.getOriginLock,
|
|
400
|
+
}) :
|
|
401
|
+
this.#createV1Agent(type, {
|
|
402
|
+
...baseOptions,
|
|
403
|
+
allowedOrigin: this.allowedOrigin,
|
|
404
|
+
});
|
|
400
405
|
}
|
|
401
406
|
|
|
402
407
|
#createV1Agent(type: ConversationType, options: AgentOptions): AiAgent<unknown> {
|
|
@@ -553,19 +558,40 @@ export class AiConversation {
|
|
|
553
558
|
}
|
|
554
559
|
|
|
555
560
|
/**
|
|
556
|
-
* Returns the
|
|
557
|
-
*
|
|
561
|
+
* Returns the conversation's origin-locking state:
|
|
562
|
+
* - `BLOCKED_BY_NAVIGATION`: An unapproved cross-origin navigation occurred during the active run.
|
|
563
|
+
* - `ESTABLISHED_ORIGIN`: The conversation is locked to the established origin.
|
|
564
|
+
* - `UNINITIALIZED`: No origin lock has been established yet.
|
|
558
565
|
*/
|
|
559
|
-
|
|
566
|
+
getOriginLock = (): OriginLockState => {
|
|
560
567
|
if (this.#navigationOccurredDuringRun) {
|
|
561
|
-
return {
|
|
568
|
+
return {status: 'BLOCKED_BY_NAVIGATION'};
|
|
562
569
|
}
|
|
563
570
|
if (this.#origin) {
|
|
564
|
-
return {origin: this.#origin};
|
|
571
|
+
return {status: 'ESTABLISHED_ORIGIN', origin: this.#origin};
|
|
572
|
+
}
|
|
573
|
+
const pageOrigin = getPrimaryPageSecurityOrigin(this.#targetManager);
|
|
574
|
+
if (pageOrigin) {
|
|
575
|
+
this.#origin = pageOrigin;
|
|
576
|
+
return {status: 'ESTABLISHED_ORIGIN', origin: this.#origin};
|
|
565
577
|
}
|
|
566
|
-
this.#origin = getPrimaryPageSecurityOrigin(this.#targetManager);
|
|
567
578
|
|
|
568
|
-
return {
|
|
579
|
+
return {status: 'UNINITIALIZED'};
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Returns the permitted origin for legacy V1 agent tool execution.
|
|
584
|
+
* Maps the OriginLockState to the AllowedOriginResult format expected by V1 agents.
|
|
585
|
+
*/
|
|
586
|
+
allowedOrigin = (): AllowedOriginResult => {
|
|
587
|
+
const lock = this.getOriginLock();
|
|
588
|
+
if (lock.status === 'BLOCKED_BY_NAVIGATION') {
|
|
589
|
+
return {blocked: true};
|
|
590
|
+
}
|
|
591
|
+
if (lock.status === 'ESTABLISHED_ORIGIN') {
|
|
592
|
+
return {origin: lock.origin};
|
|
593
|
+
}
|
|
594
|
+
return {origin: undefined};
|
|
569
595
|
};
|
|
570
596
|
}
|
|
571
597
|
|
|
@@ -11,7 +11,10 @@ import {ChangeManager} from '../ChangeManager.js';
|
|
|
11
11
|
import {LighthouseFormatter} from '../data_formatters/LighthouseFormatter.js';
|
|
12
12
|
import {debugLog} from '../debug.js';
|
|
13
13
|
import {ExtensionScope} from '../ExtensionScope.js';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
type OriginLockState,
|
|
16
|
+
ToolName,
|
|
17
|
+
} from '../tools/Tool.js';
|
|
15
18
|
import {ToolRegistry} from '../tools/ToolRegistry.js';
|
|
16
19
|
|
|
17
20
|
import {
|
|
@@ -253,7 +256,11 @@ export class AccessibilityAgent extends AiAgent<LHModel.ReporterTypes.ReportJSON
|
|
|
253
256
|
createExtensionScope: this.#createExtensionScope.bind(this),
|
|
254
257
|
execJs: this.#execJs,
|
|
255
258
|
getExecutionContextNode: () => this.#getDocumentBodyNode(),
|
|
256
|
-
|
|
259
|
+
getOriginLock: (): OriginLockState => {
|
|
260
|
+
// V1 AccessibilityAgent adapts the selected node's security origin to OriginLockState.
|
|
261
|
+
const origin = this.context?.getOrigin();
|
|
262
|
+
return origin ? {status: 'ESTABLISHED_ORIGIN', origin} : {status: 'UNINITIALIZED'};
|
|
263
|
+
},
|
|
257
264
|
},
|
|
258
265
|
options,
|
|
259
266
|
);
|
|
@@ -20,6 +20,7 @@ import {StorageContext} from '../contexts/StorageContext.js';
|
|
|
20
20
|
import {formatBytesToKb, seconds} from '../data_formatters/UnitFormatters.js';
|
|
21
21
|
import {debugLog} from '../debug.js';
|
|
22
22
|
import {StorageItem} from '../StorageItem.js';
|
|
23
|
+
import {isOriginAllowedByLock} from '../tools/Tool.js';
|
|
23
24
|
|
|
24
25
|
import {
|
|
25
26
|
type AgentOptions,
|
|
@@ -587,4 +588,29 @@ export class ContextSelectionAgent extends AiAgent<never> {
|
|
|
587
588
|
|
|
588
589
|
return [...uiSourceCodes.values()];
|
|
589
590
|
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Resolves a workspace source file by its ID, ensuring that the file's security
|
|
594
|
+
* origin is authorized by the conversation's established origin lock.
|
|
595
|
+
*
|
|
596
|
+
* Fails closed by returning `undefined` if the established origin is missing or opaque,
|
|
597
|
+
* if the file ID is invalid, or if the file origin does not match the lock.
|
|
598
|
+
*/
|
|
599
|
+
static getSourceById(
|
|
600
|
+
id: number,
|
|
601
|
+
establishedOrigin?: SDK.SecurityOrigin.SecurityOrigin,
|
|
602
|
+
// eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
|
|
603
|
+
workspace: Workspace.Workspace.WorkspaceImpl = Workspace.Workspace.WorkspaceImpl.instance(),
|
|
604
|
+
): Workspace.UISourceCode.UISourceCode|undefined {
|
|
605
|
+
if (!establishedOrigin || !Number.isInteger(id) || id <= 0) {
|
|
606
|
+
return undefined;
|
|
607
|
+
}
|
|
608
|
+
return ContextSelectionAgent.getUISourceCodes(workspace).find(file => {
|
|
609
|
+
if (ContextSelectionAgent.uiSourceCodeId.get(file) !== id) {
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
return isOriginAllowedByLock({status: 'ESTABLISHED_ORIGIN', origin: establishedOrigin},
|
|
613
|
+
FileContext.originForUISourceCode(file));
|
|
614
|
+
});
|
|
615
|
+
}
|
|
590
616
|
}
|
|
@@ -8,7 +8,10 @@ import type * as SDK from '../../../core/sdk/sdk.js';
|
|
|
8
8
|
import {ChangeManager} from '../ChangeManager.js';
|
|
9
9
|
import {ExtensionScope} from '../ExtensionScope.js';
|
|
10
10
|
import {AI_ASSISTANCE_CSS_CLASS_NAME} from '../injected.js';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
type OriginLockState,
|
|
13
|
+
ToolName,
|
|
14
|
+
} from '../tools/Tool.js';
|
|
12
15
|
import {ToolRegistry} from '../tools/ToolRegistry.js';
|
|
13
16
|
|
|
14
17
|
import {
|
|
@@ -154,8 +157,10 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
154
157
|
}
|
|
155
158
|
return await getStylesTool.handler(args, {
|
|
156
159
|
getTarget: () => this.targetManager.primaryPageTarget() ?? context.getItem().domModel().target(),
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
getOriginLock: (): OriginLockState => {
|
|
161
|
+
// V1 StylingAgent adapts the selected DOM node's security origin to OriginLockState.
|
|
162
|
+
const origin = context.getOrigin();
|
|
163
|
+
return origin ? {status: 'ESTABLISHED_ORIGIN', origin} : {status: 'UNINITIALIZED'};
|
|
159
164
|
},
|
|
160
165
|
});
|
|
161
166
|
},
|
|
@@ -176,7 +181,11 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
176
181
|
createExtensionScope: this.#createExtensionScope.bind(this),
|
|
177
182
|
execJs: this.#execJs,
|
|
178
183
|
getExecutionContextNode: () => this.context?.getItem() ?? null,
|
|
179
|
-
|
|
184
|
+
getOriginLock: (): OriginLockState => {
|
|
185
|
+
// V1 StylingAgent adapts the selected DOM node's security origin to OriginLockState.
|
|
186
|
+
const origin = this.context?.getOrigin();
|
|
187
|
+
return origin ? {status: 'ESTABLISHED_ORIGIN', origin} : {status: 'UNINITIALIZED'};
|
|
188
|
+
},
|
|
180
189
|
},
|
|
181
190
|
options,
|
|
182
191
|
),
|
|
@@ -46,18 +46,18 @@ import * as ExecuteJavaScript from './tools/ExecuteJavaScript.js';
|
|
|
46
46
|
import * as GetCookieValues from './tools/GetCookieValues.js';
|
|
47
47
|
import * as GetDetailedCallTree from './tools/GetDetailedCallTree.js';
|
|
48
48
|
import * as GetElementAccessibilityDetails from './tools/GetElementAccessibilityDetails.js';
|
|
49
|
-
import * as GetFunctionCode from './tools/GetFunctionCode.js';
|
|
50
49
|
import * as GetInsightDetails from './tools/GetInsightDetails.js';
|
|
51
50
|
import * as GetLighthouseAudits from './tools/GetLighthouseAudits.js';
|
|
52
51
|
import * as GetNetworkRequestDetails from './tools/GetNetworkRequestDetails.js';
|
|
53
|
-
import * as GetResourceContent from './tools/GetResourceContent.js';
|
|
54
52
|
import * as GetSourceContent from './tools/GetSourceContent.js';
|
|
55
53
|
import * as GetStorageBreakdown from './tools/GetStorageBreakdown.js';
|
|
56
54
|
import * as GetStorageValues from './tools/GetStorageValues.js';
|
|
57
55
|
import * as GetStyles from './tools/GetStyles.js';
|
|
58
56
|
import * as GetTraceEventByKey from './tools/GetTraceEventByKey.js';
|
|
57
|
+
import * as GetTraceFunctionCode from './tools/GetTraceFunctionCode.js';
|
|
59
58
|
import * as GetTraceMainThreadSummary from './tools/GetTraceMainThreadSummary.js';
|
|
60
59
|
import * as GetTraceNetworkSummary from './tools/GetTraceNetworkSummary.js';
|
|
60
|
+
import * as GetTraceResourceContent from './tools/GetTraceResourceContent.js';
|
|
61
61
|
import * as ListCookies from './tools/ListCookies.js';
|
|
62
62
|
import * as ListNetworkRequests from './tools/ListNetworkRequests.js';
|
|
63
63
|
import * as ListPageOrigins from './tools/ListPageOrigins.js';
|
|
@@ -99,18 +99,18 @@ export {
|
|
|
99
99
|
GetCookieValues,
|
|
100
100
|
GetDetailedCallTree,
|
|
101
101
|
GetElementAccessibilityDetails,
|
|
102
|
-
GetFunctionCode,
|
|
103
102
|
GetInsightDetails,
|
|
104
103
|
GetLighthouseAudits,
|
|
105
104
|
GetNetworkRequestDetails,
|
|
106
|
-
GetResourceContent,
|
|
107
105
|
GetSourceContent,
|
|
108
106
|
GetStorageBreakdown,
|
|
109
107
|
GetStorageValues,
|
|
110
108
|
GetStyles,
|
|
111
109
|
GetTraceEventByKey,
|
|
110
|
+
GetTraceFunctionCode,
|
|
112
111
|
GetTraceMainThreadSummary,
|
|
113
112
|
GetTraceNetworkSummary,
|
|
113
|
+
GetTraceResourceContent,
|
|
114
114
|
Injected,
|
|
115
115
|
LighthouseFormatter,
|
|
116
116
|
ListCookies,
|
|
@@ -8,8 +8,8 @@ allowed-tools:
|
|
|
8
8
|
- getTraceMainThreadSummary
|
|
9
9
|
- getTraceNetworkSummary
|
|
10
10
|
- getDetailedCallTree
|
|
11
|
-
-
|
|
12
|
-
-
|
|
11
|
+
- getTraceFunctionCode
|
|
12
|
+
- getTraceResourceContent
|
|
13
13
|
- getInsightDetails
|
|
14
14
|
---
|
|
15
15
|
You are an expert web performance assistant integrated into Chrome DevTools.
|
|
@@ -29,7 +29,8 @@ Your goal is to provide actionable advice about web page performance by analyzin
|
|
|
29
29
|
3. **Call Tree, Event & Source Inspection**:
|
|
30
30
|
- Use `getDetailedCallTree` to retrieve bottom-up execution trees for expensive main thread tasks.
|
|
31
31
|
- Use `getTraceEventByKey` to inspect timing and payload data for individual events.
|
|
32
|
-
- Use `
|
|
32
|
+
- Use `getTraceFunctionCode` to inspect a specific function identified in the call tree, including line-by-line CPU profile execution costs.
|
|
33
|
+
- Use `getTraceResourceContent` to inspect the full text of a script or resource captured within the trace by URL.
|
|
33
34
|
|
|
34
35
|
4. **UI Selection & Trace Recording**:
|
|
35
36
|
- Use `selectTraceEventByKey` to reveal and select an event in the Performance Flamechart if requested.
|
|
@@ -6,7 +6,7 @@ import * as SDK from '../../../core/sdk/sdk.js';
|
|
|
6
6
|
import type * as Protocol from '../../../generated/protocol.js';
|
|
7
7
|
|
|
8
8
|
import {MAX_TARGET_ORIGINS} from './DOMStorageUtils.js';
|
|
9
|
-
import type
|
|
9
|
+
import {isOriginAllowedByLock, type OriginLockCapability, resolveOriginFromLock} from './Tool.js';
|
|
10
10
|
|
|
11
11
|
export interface CookieDetails {
|
|
12
12
|
name: string;
|
|
@@ -25,14 +25,14 @@ export interface CookieDetails {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Resolves and validates target origins against the
|
|
28
|
+
* Resolves and validates target origins against the conversation's origin lock state and primary page target.
|
|
29
29
|
*
|
|
30
30
|
* When `requestedOrigins` is empty or omitted, defaults to the established context origin.
|
|
31
31
|
* Rejects opaque origins, mismatches with the primary page origin, and cross-origin targets.
|
|
32
32
|
* Limits results to at most `MAX_TARGET_ORIGINS` unique origins.
|
|
33
33
|
*
|
|
34
34
|
* @param requestedOrigins Optional list of origin URLs to validate.
|
|
35
|
-
* @param context The origin lock capability
|
|
35
|
+
* @param context The origin lock capability providing access to the conversation's origin lock state.
|
|
36
36
|
* @param targetManager The target manager used to resolve the primary page target.
|
|
37
37
|
* @returns An object with validated target origins and the primary page target, or an error object.
|
|
38
38
|
*/
|
|
@@ -44,10 +44,12 @@ export function resolveAllowedTargetOrigins(
|
|
|
44
44
|
error: string,
|
|
45
45
|
}
|
|
46
46
|
{
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
const originLock = context.getOriginLock();
|
|
48
|
+
const originResult = resolveOriginFromLock(originLock);
|
|
49
|
+
if ('error' in originResult) {
|
|
50
|
+
return originResult;
|
|
50
51
|
}
|
|
52
|
+
const establishedOrigin = originResult.origin;
|
|
51
53
|
|
|
52
54
|
const primaryPageTarget = targetManager.primaryPageTarget();
|
|
53
55
|
if (!primaryPageTarget) {
|
|
@@ -55,7 +57,7 @@ export function resolveAllowedTargetOrigins(
|
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
const pageOrigin = primaryPageTarget.inspectedSecurityOrigin();
|
|
58
|
-
if (!pageOrigin
|
|
60
|
+
if (!isOriginAllowedByLock(originLock, pageOrigin)) {
|
|
59
61
|
return {error: 'Page origin does not match allowed origin.'};
|
|
60
62
|
}
|
|
61
63
|
|
|
@@ -65,7 +67,7 @@ export function resolveAllowedTargetOrigins(
|
|
|
65
67
|
[establishedOrigin];
|
|
66
68
|
|
|
67
69
|
const validOrigins =
|
|
68
|
-
candidateOrigins.filter(origin => origin
|
|
70
|
+
candidateOrigins.filter(origin => isOriginAllowedByLock(originLock, origin)).map(origin => origin.siteId());
|
|
69
71
|
|
|
70
72
|
const targetOrigins = Array.from(new Set(validOrigins)).slice(0, MAX_TARGET_ORIGINS);
|
|
71
73
|
if (targetOrigins.length === 0) {
|
|
@@ -131,7 +131,7 @@ const data = {
|
|
|
131
131
|
return {error: 'Error: Could not find the context node for execution.'};
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
if (!isOriginAllowedByLock(context.
|
|
134
|
+
if (!isOriginAllowedByLock(context.getOriginLock(), executionNode.securityOrigin())) {
|
|
135
135
|
return {error: 'Error: Cannot execute JavaScript on cross-origin target.'};
|
|
136
136
|
}
|
|
137
137
|
|
|
@@ -80,8 +80,6 @@ export class GetElementAccessibilityDetailsTool implements
|
|
|
80
80
|
params: GetElementAccessibilityDetailsArgs,
|
|
81
81
|
context: BaseToolCapability&TargetCapability&OriginLockCapability,
|
|
82
82
|
): Promise<DataHandlerResult<string>> {
|
|
83
|
-
const establishedOrigin = context.getEstablishedOrigin();
|
|
84
|
-
|
|
85
83
|
const target = context.getTarget();
|
|
86
84
|
if (!target) {
|
|
87
85
|
return {error: 'Error: Inspected target not found.'};
|
|
@@ -99,7 +97,7 @@ export class GetElementAccessibilityDetailsTool implements
|
|
|
99
97
|
// Security check: Ensure the element matches the active conversation's origin lock.
|
|
100
98
|
// Because getTarget() returns the primary page target to support resolving elements
|
|
101
99
|
// across frames, origin validation must be enforced directly on the resolved node.
|
|
102
|
-
if (!isOriginAllowedByLock(
|
|
100
|
+
if (!isOriginAllowedByLock(context.getOriginLock(), resolved.securityOrigin())) {
|
|
103
101
|
return {error: 'Error: Node does not belong to the current origin.'};
|
|
104
102
|
}
|
|
105
103
|
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type DataTool,
|
|
15
15
|
isOriginAllowedByLock,
|
|
16
16
|
type OriginLockCapability,
|
|
17
|
+
resolveOriginFromLock,
|
|
17
18
|
type ToolArgs,
|
|
18
19
|
ToolName,
|
|
19
20
|
} from './Tool.js';
|
|
@@ -75,9 +76,12 @@ export class GetNetworkRequestDetailsTool implements
|
|
|
75
76
|
args: GetNetworkRequestDetailsArgs,
|
|
76
77
|
context: BaseToolCapability&OriginLockCapability,
|
|
77
78
|
): Promise<DataHandlerResult<unknown>> {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
const originLock = context.getOriginLock();
|
|
80
|
+
const originResult = resolveOriginFromLock(originLock);
|
|
81
|
+
if ('error' in originResult) {
|
|
82
|
+
return originResult;
|
|
83
|
+
}
|
|
84
|
+
const establishedOrigin = originResult.origin;
|
|
81
85
|
|
|
82
86
|
// eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
|
|
83
87
|
const networkLog = this.#networkLog ?? Logs.NetworkLog.NetworkLog.instance();
|
|
@@ -87,13 +91,10 @@ export class GetNetworkRequestDetailsTool implements
|
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
// If the conversation is locked to an origin, only allow accessing requests from that origin.
|
|
90
|
-
return isOriginAllowedByLock(
|
|
94
|
+
return isOriginAllowedByLock(originLock, req.initiatorSecurityOrigin());
|
|
91
95
|
});
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
// so find() will never return a request. We check establishedOrigin here as a defensive
|
|
95
|
-
// guard and to narrow the type for NetworkRequestFormatter below.
|
|
96
|
-
if (!establishedOrigin || !request) {
|
|
97
|
+
if (!request) {
|
|
97
98
|
return {
|
|
98
99
|
error: 'No request found',
|
|
99
100
|
};
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type DataHandlerResult,
|
|
14
14
|
type DataTool,
|
|
15
15
|
type OriginLockCapability,
|
|
16
|
+
resolveOriginFromLock,
|
|
16
17
|
type ToolArgs,
|
|
17
18
|
ToolName,
|
|
18
19
|
} from './Tool.js';
|
|
@@ -64,14 +65,12 @@ export class GetSourceContentTool implements
|
|
|
64
65
|
args: GetSourceContentArgs,
|
|
65
66
|
context: BaseToolCapability&OriginLockCapability,
|
|
66
67
|
): Promise<DataHandlerResult<{content: string}>> {
|
|
67
|
-
const
|
|
68
|
-
if (
|
|
69
|
-
return
|
|
70
|
-
error: 'Unable to find file.',
|
|
71
|
-
};
|
|
68
|
+
const originResult = resolveOriginFromLock(context.getOriginLock());
|
|
69
|
+
if ('error' in originResult) {
|
|
70
|
+
return originResult;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
const file = ListSourcesTool.getSourceById(args.id,
|
|
73
|
+
const file = ListSourcesTool.getSourceById(args.id, originResult.origin);
|
|
75
74
|
|
|
76
75
|
if (!file) {
|
|
77
76
|
return {
|
|
@@ -8,7 +8,8 @@ import * as Platform from '../../../core/platform/platform.js';
|
|
|
8
8
|
import * as SDK from '../../../core/sdk/sdk.js';
|
|
9
9
|
import type {FunctionHandlerOptions} from '../agents/AiAgent.js';
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import {resolveAllowedTargetOrigins} from './CookieUtils.js';
|
|
12
|
+
import {resolveDOMStorages} from './DOMStorageUtils.js';
|
|
12
13
|
import {
|
|
13
14
|
type BaseToolCapability,
|
|
14
15
|
type DataHandlerResult,
|
|
@@ -112,31 +113,11 @@ export class GetStorageValuesTool implements DataTool<GetStorageValuesArgs, GetS
|
|
|
112
113
|
|
|
113
114
|
// eslint-disable-next-line @devtools/no-instance-of-migrated-singletons
|
|
114
115
|
const targetManager = SDK.TargetManager.TargetManager.instance();
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (!establishedOrigin || establishedOrigin.isOpaque()) {
|
|
119
|
-
return {error: 'No origin available or not allowed.'};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (!primaryPageTarget) {
|
|
123
|
-
return {error: 'No origin available or not allowed.'};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const pageOrigin = primaryPageTarget.inspectedSecurityOrigin();
|
|
127
|
-
if (!pageOrigin.isSameOriginWith(establishedOrigin)) {
|
|
128
|
-
return {error: 'No origin available or not allowed.'};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const candidateOrigins: SDK.SecurityOrigin.SecurityOrigin[] = (args.origins && args.origins.length > 0) ?
|
|
132
|
-
args.origins.map(origin => SDK.SecurityOrigin.SecurityOrigin.create(origin)) :
|
|
133
|
-
[establishedOrigin];
|
|
134
|
-
const validOrigins =
|
|
135
|
-
candidateOrigins.filter(origin => origin.isSameOriginWith(establishedOrigin)).map(origin => origin.siteId());
|
|
136
|
-
const targetOrigins = Array.from(new Set(validOrigins)).slice(0, MAX_TARGET_ORIGINS);
|
|
137
|
-
if (targetOrigins.length === 0) {
|
|
138
|
-
return {error: 'No valid origins found.'};
|
|
116
|
+
const targetOriginsResult = resolveAllowedTargetOrigins(args.origins, context, targetManager);
|
|
117
|
+
if ('error' in targetOriginsResult) {
|
|
118
|
+
return {error: targetOriginsResult.error};
|
|
139
119
|
}
|
|
120
|
+
const {targetOrigins, primaryPageTarget} = targetOriginsResult;
|
|
140
121
|
|
|
141
122
|
const storageKey = (targetOrigins.length === 1 && args.storageKey) ? args.storageKey : undefined;
|
|
142
123
|
|
|
@@ -97,8 +97,6 @@ export class GetStylesTool implements
|
|
|
97
97
|
return {error: 'Error: Could not find the inspected page.'};
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
const establishedOrigin = context.getEstablishedOrigin();
|
|
101
|
-
|
|
102
100
|
for (const uid of params.elements) {
|
|
103
101
|
result[uid] = {computed: {}, authored: {}};
|
|
104
102
|
const node = new SDK.DOMModel.DeferredDOMNode(target, uid as Protocol.DOM.BackendNodeId);
|
|
@@ -109,7 +107,7 @@ export class GetStylesTool implements
|
|
|
109
107
|
// Security check: Ensure the resolved element belongs to the locked origin.
|
|
110
108
|
// Because getTarget() returns the primary page target to support resolving elements
|
|
111
109
|
// across frames, origin validation must be enforced directly on the resolved node.
|
|
112
|
-
if (!isOriginAllowedByLock(
|
|
110
|
+
if (!isOriginAllowedByLock(context.getOriginLock(), resolved.securityOrigin())) {
|
|
113
111
|
return {error: 'Error: Node does not belong to the current origin.'};
|
|
114
112
|
}
|
|
115
113
|
const styles = await resolved.domModel().cssModel().getComputedStyle(resolved.id);
|
|
@@ -21,54 +21,67 @@ const UIStringsNotTranslate = {
|
|
|
21
21
|
|
|
22
22
|
const lockedString = i18n.i18n.lockedString;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Arguments for {@link GetTraceFunctionCodeTool}.
|
|
26
|
+
*/
|
|
27
|
+
export interface GetTraceFunctionCodeArgs extends ToolArgs {
|
|
28
|
+
/** The URL of the script containing the function recorded in the performance trace. */
|
|
25
29
|
scriptUrl: string;
|
|
30
|
+
/** The line number where the function is defined (0-based, as reported in the call tree). */
|
|
26
31
|
line: number;
|
|
32
|
+
/** The column number where the function is defined (0-based, as reported in the call tree). */
|
|
27
33
|
column: number;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Retrieves function code and line-by-line CPU profile execution costs from the performance trace.
|
|
38
|
+
*
|
|
39
|
+
* Preconditions:
|
|
40
|
+
* - Requires an active, freshly recorded trace session (fails on imported traces).
|
|
41
|
+
* - Requires resource access via the performance trace context.
|
|
42
|
+
*/
|
|
43
|
+
export class GetTraceFunctionCodeTool implements
|
|
44
|
+
DataTool<GetTraceFunctionCodeArgs, string, BaseToolCapability&PerformanceTraceCapability> {
|
|
45
|
+
readonly name: ToolName = ToolName.GET_TRACE_FUNCTION_CODE;
|
|
33
46
|
readonly description: string =
|
|
34
|
-
'Retrieves the code for a function
|
|
47
|
+
'Retrieves the code for a function recorded in the performance trace at the specified location, annotated with line-by-line CPU runtime profiling execution costs. Do not call this tool unless a performance trace recording is actively loaded.';
|
|
35
48
|
|
|
36
|
-
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof
|
|
49
|
+
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetTraceFunctionCodeArgs> = {
|
|
37
50
|
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
38
|
-
description: 'Arguments for looking up function code.',
|
|
51
|
+
description: 'Arguments for looking up function code from the performance trace profile.',
|
|
39
52
|
nullable: false,
|
|
40
53
|
properties: {
|
|
41
54
|
scriptUrl: {
|
|
42
55
|
type: Host.AidaClient.ParametersTypes.STRING,
|
|
43
|
-
description: 'The
|
|
56
|
+
description: 'The URL of the script containing the function recorded in the performance trace.',
|
|
44
57
|
nullable: false,
|
|
45
58
|
},
|
|
46
59
|
line: {
|
|
47
60
|
type: Host.AidaClient.ParametersTypes.INTEGER,
|
|
48
|
-
description: 'The line number where the function is defined.',
|
|
61
|
+
description: 'The line number where the function is defined (0-based, as reported in the call tree).',
|
|
49
62
|
nullable: false,
|
|
50
63
|
},
|
|
51
64
|
column: {
|
|
52
65
|
type: Host.AidaClient.ParametersTypes.INTEGER,
|
|
53
|
-
description: 'The column number where the function is defined.',
|
|
66
|
+
description: 'The column number where the function is defined (0-based, as reported in the call tree).',
|
|
54
67
|
nullable: false,
|
|
55
68
|
},
|
|
56
69
|
},
|
|
57
70
|
required: ['scriptUrl', 'line', 'column'],
|
|
58
71
|
};
|
|
59
72
|
|
|
60
|
-
displayInfoFromArgs(params:
|
|
73
|
+
displayInfoFromArgs(params: GetTraceFunctionCodeArgs): {
|
|
61
74
|
title: string,
|
|
62
75
|
action: string,
|
|
63
76
|
} {
|
|
64
77
|
return {
|
|
65
78
|
title: lockedString(UIStringsNotTranslate.lookingUpFunctionCode),
|
|
66
|
-
action: `
|
|
79
|
+
action: `getTraceFunctionCode('${params.scriptUrl}', ${params.line}, ${params.column})`,
|
|
67
80
|
};
|
|
68
81
|
}
|
|
69
82
|
|
|
70
83
|
async handler(
|
|
71
|
-
params:
|
|
84
|
+
params: GetTraceFunctionCodeArgs,
|
|
72
85
|
capabilities: BaseToolCapability&PerformanceTraceCapability,
|
|
73
86
|
): Promise<DataHandlerResult<string>> {
|
|
74
87
|
const performanceTraceContext = capabilities.getPerformanceTraceContext();
|
package/front_end/models/ai_assistance/tools/{GetResourceContent.ts → GetTraceResourceContent.ts}
RENAMED
|
@@ -25,42 +25,57 @@ const UIStringsNotTranslate = {
|
|
|
25
25
|
|
|
26
26
|
const lockedString = i18n.i18n.lockedString;
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Arguments for {@link GetTraceResourceContentTool}.
|
|
30
|
+
*/
|
|
31
|
+
export interface GetTraceResourceContentArgs extends ToolArgs {
|
|
32
|
+
/** The URL of the resource captured in the performance trace to retrieve. */
|
|
29
33
|
url: string;
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Retrieves text content for a resource or script captured in the performance trace.
|
|
38
|
+
*
|
|
39
|
+
* Precedence:
|
|
40
|
+
* 1. Checks trace metadata (`parsedTrace.data.Scripts`) for scripts captured during recording.
|
|
41
|
+
* 2. Falls back to querying the live page target's `ResourceTreeModel`.
|
|
42
|
+
*
|
|
43
|
+
* Preconditions:
|
|
44
|
+
* - Requires an active, freshly recorded trace session (fails on imported traces).
|
|
45
|
+
* - Fails if resource is binary/non-text, cross-origin, or a `file://` URL.
|
|
46
|
+
*/
|
|
47
|
+
export class GetTraceResourceContentTool implements DataTool<
|
|
48
|
+
GetTraceResourceContentArgs, {content: string}, BaseToolCapability&TargetCapability&PerformanceTraceCapability> {
|
|
49
|
+
readonly name: ToolName = ToolName.GET_TRACE_RESOURCE_CONTENT;
|
|
35
50
|
readonly description: string =
|
|
36
|
-
'Retrieves the content of
|
|
51
|
+
'Retrieves the text content of a script or resource captured within the recorded performance trace by URL. Only use this for text resource types. Do not call this tool on imported traces or for general workspace files (use listSources and getSourceContent instead).';
|
|
37
52
|
|
|
38
|
-
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof
|
|
53
|
+
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetTraceResourceContentArgs> = {
|
|
39
54
|
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
40
|
-
description: 'Arguments for looking up resource content.',
|
|
55
|
+
description: 'Arguments for looking up resource content from the performance trace.',
|
|
41
56
|
nullable: false,
|
|
42
57
|
properties: {
|
|
43
58
|
url: {
|
|
44
59
|
type: Host.AidaClient.ParametersTypes.STRING,
|
|
45
|
-
description: 'The
|
|
60
|
+
description: 'The URL of the resource captured in the performance trace to retrieve.',
|
|
46
61
|
nullable: false,
|
|
47
62
|
},
|
|
48
63
|
},
|
|
49
64
|
required: ['url'],
|
|
50
65
|
};
|
|
51
66
|
|
|
52
|
-
displayInfoFromArgs(params:
|
|
67
|
+
displayInfoFromArgs(params: GetTraceResourceContentArgs): {
|
|
53
68
|
title: string,
|
|
54
69
|
action: string,
|
|
55
70
|
} {
|
|
56
71
|
return {
|
|
57
72
|
title: lockedString(UIStringsNotTranslate.lookingAtResourceContent),
|
|
58
|
-
action: `
|
|
73
|
+
action: `getTraceResourceContent('${params.url}')`,
|
|
59
74
|
};
|
|
60
75
|
}
|
|
61
76
|
|
|
62
77
|
async handler(
|
|
63
|
-
params:
|
|
78
|
+
params: GetTraceResourceContentArgs,
|
|
64
79
|
capabilities: BaseToolCapability&TargetCapability&PerformanceTraceCapability,
|
|
65
80
|
): Promise<DataHandlerResult<{content: string}>> {
|
|
66
81
|
const performanceTraceContext = capabilities.getPerformanceTraceContext();
|
|
@@ -72,6 +87,10 @@ export class GetResourceContentTool implements DataTool<
|
|
|
72
87
|
return {error: 'Cannot use this tool on an imported file.'};
|
|
73
88
|
}
|
|
74
89
|
|
|
90
|
+
if (!params.url) {
|
|
91
|
+
return {error: 'Missing arg: url'};
|
|
92
|
+
}
|
|
93
|
+
|
|
75
94
|
if (!performanceTraceContext.canAccessResource(params.url)) {
|
|
76
95
|
return {error: 'Resource not found'};
|
|
77
96
|
}
|
|
@@ -82,6 +101,7 @@ export class GetResourceContentTool implements DataTool<
|
|
|
82
101
|
let content: string;
|
|
83
102
|
|
|
84
103
|
const url = params.url as Platform.DevToolsPath.UrlString;
|
|
104
|
+
// Check trace metadata for scripts captured during recording before falling back to live page resources.
|
|
85
105
|
const script = parsedTrace.data.Scripts?.scripts.find(script => script.url === params.url);
|
|
86
106
|
if (script?.content !== undefined) {
|
|
87
107
|
content = script.content;
|