chrome-devtools-frontend 1.0.1643099 → 1.0.1643855
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/eslint.config.mjs +3 -1
- package/extension-api/ExtensionAPI.d.ts +83 -12
- package/front_end/core/host/UserMetrics.ts +0 -1
- package/front_end/core/root/ExperimentNames.ts +0 -1
- package/front_end/core/sdk/ConsoleModel.ts +4 -0
- package/front_end/core/sdk/NetworkRequest.ts +12 -0
- package/front_end/core/sdk/SourceMap.ts +15 -18
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -2
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -2
- package/front_end/entrypoints/main/MainImpl.ts +0 -6
- package/front_end/models/ai_assistance/AiAgent2.ts +1 -0
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +22 -16
- package/front_end/models/ai_assistance/agents/AiAgent.ts +19 -6
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +5 -5
- package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +1 -94
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +25 -0
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +22 -0
- package/front_end/models/ai_assistance/agents/StorageAgent.ts +54 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +1 -2
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +5 -0
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +4 -10
- package/front_end/models/ai_assistance/tools/Tool.ts +6 -0
- package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +6 -9
- package/front_end/models/bindings/DefaultScriptMapping.ts +2 -1
- package/front_end/models/bindings/SymbolizedError.ts +45 -35
- package/front_end/models/extensions/ExtensionAPI.ts +138 -47
- package/front_end/models/har/Importer.ts +1 -0
- package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +12 -2
- package/front_end/models/stack_trace/DetailedErrorStackParser.ts +44 -51
- package/front_end/models/stack_trace/StackTrace.ts +7 -0
- package/front_end/models/stack_trace/StackTraceImpl.ts +13 -4
- package/front_end/models/stack_trace/StackTraceModel.ts +9 -8
- package/front_end/panels/accessibility/AccessibilitySidebarView.ts +2 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +2 -1
- package/front_end/panels/application/ApplicationPanelSidebar.ts +39 -0
- package/front_end/panels/application/ApplicationPanelTreeElement.ts +39 -0
- package/front_end/panels/application/CookieItemsView.ts +2 -2
- package/front_end/panels/application/resourcesSidebar.css +11 -0
- package/front_end/panels/console/SymbolizedErrorWidget.ts +10 -7
- package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -0
- package/front_end/panels/sources/SourcesPanel.ts +2 -1
- package/front_end/ui/legacy/StackedPane.ts +229 -0
- package/front_end/ui/legacy/ViewManager.ts +59 -169
- package/front_end/ui/legacy/legacy.ts +3 -1
- package/package.json +1 -1
|
@@ -23,7 +23,7 @@ const lockedString = i18n.i18n.lockedString;
|
|
|
23
23
|
const preamble =
|
|
24
24
|
`You are a Senior Software Engineer specializing in state audit and storage analysis within Chrome DevTools. Your mission is to help developers debug storage-related issues faster by analyzing the evidence in LocalStorage, SessionStorage, and Cookies.
|
|
25
25
|
|
|
26
|
-
You have access to the site's storage using tools like \`listPageOrigins\`, \`listStorageKeys\`, \`getStorageValues\`, \`listCookies\`, and \`getCookieValues\`.
|
|
26
|
+
You have access to the site's storage using tools like \`getStorageBreakdown\`, \`listPageOrigins\`, \`listStorageKeys\`, \`getStorageValues\`, \`listCookies\`, and \`getCookieValues\`.
|
|
27
27
|
|
|
28
28
|
# Goals
|
|
29
29
|
|
|
@@ -34,6 +34,7 @@ const preamble =
|
|
|
34
34
|
# Tools & Workflow
|
|
35
35
|
|
|
36
36
|
- **Prioritize Top-Level Context**: Always initiate your investigation from the top-level page's storage. Explicitly state if you are analyzing storage from a different context (e.g., an iframe).
|
|
37
|
+
- **Storage Breakdown**: Calling \`getStorageBreakdown\` gives you the total usage and quota per storage for the top-level page.
|
|
37
38
|
- **Address Specific Selections**: The user can select individual storage items in the DevTools UI (provided in the '# Active Context' section of the prompt). If the query is about a selected item (e.g., "Why is this cookie set?"), focus your response on that specific item.
|
|
38
39
|
- **Expand Scope When Necessary**: For general questions or those implying a wider scope (e.g., "Check all storages," "Are there related cookies on subdomains?"), proactively use your tools to explore other relevant storage contexts, including iframes and different origins.
|
|
39
40
|
- **Discovery**: Start by calling \`listPageOrigins\` to discover all active, non-empty frame origins loaded by the page.
|
|
@@ -479,6 +480,58 @@ export class StorageAgent extends AiAgent<StorageItem> {
|
|
|
479
480
|
return {result: {cookies: cookieData}};
|
|
480
481
|
},
|
|
481
482
|
});
|
|
483
|
+
|
|
484
|
+
this.declareFunction<Record<string, never>, {
|
|
485
|
+
totalUsage: string,
|
|
486
|
+
totalQuota: string,
|
|
487
|
+
usageBreakdown: Array<{
|
|
488
|
+
storageType: string,
|
|
489
|
+
usage: string,
|
|
490
|
+
}>,
|
|
491
|
+
}>('getStorageBreakdown', {
|
|
492
|
+
description:
|
|
493
|
+
'Retrieves the total storage usage, total storage quota, and a breakdown of active storage usage per storage type for the top-level page.',
|
|
494
|
+
parameters: {
|
|
495
|
+
type: Host.AidaClient.ParametersTypes.OBJECT,
|
|
496
|
+
description: '',
|
|
497
|
+
nullable: false,
|
|
498
|
+
properties: {},
|
|
499
|
+
required: [],
|
|
500
|
+
},
|
|
501
|
+
displayInfoFromArgs: () => {
|
|
502
|
+
return {
|
|
503
|
+
title: lockedString('Retrieving storage breakdown'),
|
|
504
|
+
action: 'getStorageBreakdown()',
|
|
505
|
+
};
|
|
506
|
+
},
|
|
507
|
+
handler: async () => {
|
|
508
|
+
const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
|
|
509
|
+
if (!target || !this.context || !isSamePageOrigin(target, this.context)) {
|
|
510
|
+
return {error: 'No origin available or not allowed.'};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const origin = this.context.getOrigin();
|
|
514
|
+
const response = await target.storageAgent().invoke_getUsageAndQuota({origin});
|
|
515
|
+
if (response.getError()) {
|
|
516
|
+
return {error: response.getError() || 'Unknown CDP error'};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const usageBreakdown = response.usageBreakdown.filter(entry => entry.usage > 0)
|
|
520
|
+
.sort((a, b) => b.usage - a.usage)
|
|
521
|
+
.map(entry => ({
|
|
522
|
+
storageType: entry.storageType as string,
|
|
523
|
+
usage: i18n.ByteUtilities.bytesToString(entry.usage),
|
|
524
|
+
}));
|
|
525
|
+
|
|
526
|
+
return {
|
|
527
|
+
result: {
|
|
528
|
+
totalUsage: i18n.ByteUtilities.bytesToString(response.usage),
|
|
529
|
+
totalQuota: i18n.ByteUtilities.bytesToString(response.quota),
|
|
530
|
+
usageBreakdown,
|
|
531
|
+
},
|
|
532
|
+
};
|
|
533
|
+
},
|
|
534
|
+
});
|
|
482
535
|
}
|
|
483
536
|
|
|
484
537
|
static #formatContext(item: StorageItem): string {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
Title: StylingAgent buildRequest structure matches the snapshot
|
|
3
2
|
Content:
|
|
4
3
|
{
|
|
@@ -129,7 +128,7 @@ Content:
|
|
|
129
128
|
"disable_user_content_logging": false,
|
|
130
129
|
"string_session_id": "sessionId",
|
|
131
130
|
"user_tier": 3,
|
|
132
|
-
"client_version": "unit_test"
|
|
131
|
+
"client_version": "unit_test+function_calling"
|
|
133
132
|
},
|
|
134
133
|
"functionality_type": 5,
|
|
135
134
|
"client_feature": 2
|
|
@@ -211,6 +211,7 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
211
211
|
changeManager: this.#changes,
|
|
212
212
|
createExtensionScope: this.#createExtensionScope.bind(this),
|
|
213
213
|
execJs: this.#execJs,
|
|
214
|
+
getExecutionContextNode: () => this.context?.getItem() ?? null,
|
|
214
215
|
},
|
|
215
216
|
options,
|
|
216
217
|
),
|
|
@@ -280,6 +281,10 @@ export class StylingAgent extends AiAgent<SDK.DOMModel.DOMNode> {
|
|
|
280
281
|
});
|
|
281
282
|
}
|
|
282
283
|
|
|
284
|
+
override preambleFeatures(): string[] {
|
|
285
|
+
return ['function_calling'];
|
|
286
|
+
}
|
|
287
|
+
|
|
283
288
|
#getSelectedNode(): SDK.DOMModel.DOMNode|null {
|
|
284
289
|
return this.context?.getItem() ?? null;
|
|
285
290
|
}
|
|
@@ -6,7 +6,6 @@ import * as Host from '../../../core/host/host.js';
|
|
|
6
6
|
import * as Root from '../../../core/root/root.js';
|
|
7
7
|
import type {FunctionCallHandlerResult, FunctionHandlerOptions,} from '../agents/AiAgent.js';
|
|
8
8
|
import {JavascriptExecutor} from '../agents/ExecuteJavascript.js';
|
|
9
|
-
import {DOMNodeContext} from '../contexts/DOMNodeContext.js';
|
|
10
9
|
|
|
11
10
|
import {
|
|
12
11
|
type Tool,
|
|
@@ -108,14 +107,9 @@ const data = {
|
|
|
108
107
|
context: ToolContext,
|
|
109
108
|
options?: FunctionHandlerOptions,
|
|
110
109
|
): Promise<FunctionCallHandlerResult<unknown>> {
|
|
111
|
-
const
|
|
112
|
-
if (!
|
|
113
|
-
return {error: 'Error: Could not find the
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const selectedNode = activeContext.getItem();
|
|
117
|
-
if (!selectedNode) {
|
|
118
|
-
return {error: 'Error: Could not find the currently selected element.'};
|
|
110
|
+
const executionNode = context.getExecutionContextNode?.() ?? null;
|
|
111
|
+
if (!executionNode) {
|
|
112
|
+
return {error: 'Error: Could not find the context node for execution.'};
|
|
119
113
|
}
|
|
120
114
|
|
|
121
115
|
const executionMode = Root.Runtime.hostConfig.devToolsFreestyler?.executionMode ??
|
|
@@ -129,7 +123,7 @@ const data = {
|
|
|
129
123
|
|
|
130
124
|
const executor = new JavascriptExecutor({
|
|
131
125
|
executionMode,
|
|
132
|
-
getContextNode: () =>
|
|
126
|
+
getContextNode: () => executionNode,
|
|
133
127
|
createExtensionScope,
|
|
134
128
|
changes,
|
|
135
129
|
},
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import type * as Host from '../../../core/host/host.js';
|
|
6
|
+
import type * as SDK from '../../../core/sdk/sdk.js';
|
|
6
7
|
import type {ConversationContext, FunctionCallHandlerResult, FunctionHandlerOptions} from '../agents/AiAgent.js';
|
|
7
8
|
import type {executeJsCode} from '../agents/ExecuteJavascript.js';
|
|
8
9
|
import type {ChangeManager} from '../ChangeManager.js';
|
|
@@ -17,6 +18,11 @@ export interface ToolContext {
|
|
|
17
18
|
install(): Promise<void>, uninstall(): Promise<void>,
|
|
18
19
|
};
|
|
19
20
|
execJs?: typeof executeJsCode;
|
|
21
|
+
/**
|
|
22
|
+
* Returns the DOM node that acts as the execution context (i.e. `$0` inside the execution context)
|
|
23
|
+
* for running JavaScript.
|
|
24
|
+
*/
|
|
25
|
+
getExecutionContextNode?: () => SDK.DOMModel.DOMNode | null;
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
/**
|
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
isErrorLike,
|
|
25
25
|
type SymbolizedError,
|
|
26
26
|
SymbolizedErrorObject,
|
|
27
|
-
SymbolizedSyntaxError,
|
|
28
27
|
UnparsableError,
|
|
29
28
|
} from './SymbolizedError.js';
|
|
30
29
|
|
|
@@ -238,14 +237,6 @@ export class DebuggerWorkspaceBinding implements SDK.TargetManager.SDKModelObser
|
|
|
238
237
|
]);
|
|
239
238
|
fetchedExceptionDetails = details;
|
|
240
239
|
causeRemoteObject = causeRemote;
|
|
241
|
-
|
|
242
|
-
if (remoteObject.className === 'SyntaxError' && fetchedExceptionDetails) {
|
|
243
|
-
const syntaxError = await SymbolizedSyntaxError.fromExceptionDetails(
|
|
244
|
-
remoteObject.runtimeModel().target(), this, fetchedExceptionDetails);
|
|
245
|
-
if (syntaxError) {
|
|
246
|
-
return syntaxError;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
240
|
} else if (remoteObject.type === 'string') {
|
|
250
241
|
errorStack = remoteObject.description || '';
|
|
251
242
|
if (!isErrorLike(errorStack)) {
|
|
@@ -271,6 +262,12 @@ export class DebuggerWorkspaceBinding implements SDK.TargetManager.SDKModelObser
|
|
|
271
262
|
}
|
|
272
263
|
|
|
273
264
|
const message = StackTraceImpl.DetailedErrorStackParser.parseMessage(errorStack);
|
|
265
|
+
|
|
266
|
+
if (remoteObject.subtype === 'error' && remoteObject.className === 'SyntaxError' && fetchedExceptionDetails) {
|
|
267
|
+
return await SymbolizedErrorObject.createForSyntaxError(remoteObject.runtimeModel().target(), this, message,
|
|
268
|
+
fetchedExceptionDetails, stackTrace, cause);
|
|
269
|
+
}
|
|
270
|
+
|
|
274
271
|
return new SymbolizedErrorObject(message, stackTrace, cause);
|
|
275
272
|
}
|
|
276
273
|
|
|
@@ -107,7 +107,8 @@ export class DefaultScriptMapping implements DebuggerSourceMapping {
|
|
|
107
107
|
}
|
|
108
108
|
this.#uiSourceCodeToScript.set(uiSourceCode, script);
|
|
109
109
|
this.#scriptToUISourceCode.set(script, uiSourceCode);
|
|
110
|
-
|
|
110
|
+
const mimeType = script.isWasm() ? 'application/wasm' : 'text/javascript';
|
|
111
|
+
this.#project.addUISourceCodeWithProvider(uiSourceCode, script, null, mimeType);
|
|
111
112
|
void this.#debuggerWorkspaceBinding.updateLocations(script);
|
|
112
113
|
}
|
|
113
114
|
|
|
@@ -15,7 +15,7 @@ export function isErrorLike(stack: string): boolean {
|
|
|
15
15
|
return /\n\s*at\s/.test(stack) || stack.startsWith('SyntaxError:');
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export type SymbolizedError = SymbolizedErrorObject|
|
|
18
|
+
export type SymbolizedError = SymbolizedErrorObject|UnparsableError;
|
|
19
19
|
|
|
20
20
|
export class UnparsableError extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
21
21
|
readonly errorStack: string;
|
|
@@ -45,6 +45,7 @@ export class SymbolizedErrorObject extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
45
45
|
readonly message: string;
|
|
46
46
|
readonly stackTrace: StackTrace.StackTrace.ParsedErrorStackTrace;
|
|
47
47
|
readonly cause: SymbolizedError|null;
|
|
48
|
+
#syntaxErrorLocation: Workspace.UISourceCode.UILocation|null = null;
|
|
48
49
|
|
|
49
50
|
constructor(message: string, stackTrace: StackTrace.StackTrace.ParsedErrorStackTrace, cause: SymbolizedError|null) {
|
|
50
51
|
super();
|
|
@@ -64,53 +65,62 @@ export class SymbolizedErrorObject extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
this
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export class SymbolizedSyntaxError extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
73
|
-
readonly message: string;
|
|
74
|
-
#uiLocation: Workspace.UISourceCode.UILocation|null = null;
|
|
75
|
-
|
|
76
|
-
constructor(message: string) {
|
|
77
|
-
super();
|
|
78
|
-
this.message = message;
|
|
68
|
+
get syntaxErrorLocation(): Workspace.UISourceCode.UILocation|null {
|
|
69
|
+
return this.#syntaxErrorLocation;
|
|
79
70
|
}
|
|
80
71
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Evaluates if we should populate the `syntaxErrorLocation` based on the provided exception details.
|
|
74
|
+
*
|
|
75
|
+
* There are three primary cases for SyntaxError:
|
|
76
|
+
* 1. Programmatic `SyntaxError`: Thrown via `throw new SyntaxError('...', {cause: ...})`. Has a full stack trace,
|
|
77
|
+
* and an optional cause. The exception details point to the `throw` statement, which is identical to the top frame.
|
|
78
|
+
* We do NOT want to populate `syntaxErrorLocation` here to avoid redundant location rendering in the UI.
|
|
79
|
+
* 2. Script parse failure: Failed to parse a script. Has no stack trace but possesses a compile-time location.
|
|
80
|
+
* We DO want to populate `syntaxErrorLocation` to highlight where the parse failed.
|
|
81
|
+
* 3. `eval` parse failure: Failed to parse an eval string. Has a stack trace pointing to the `eval` call site
|
|
82
|
+
* and a compile-time location of the parse failure within the string. The exception details location differs
|
|
83
|
+
* from the top frame. We DO want to populate `syntaxErrorLocation` here.
|
|
84
|
+
*/
|
|
85
|
+
static async createForSyntaxError(target: SDK.Target.Target, debuggerWorkspaceBinding: DebuggerWorkspaceBinding,
|
|
86
|
+
message: string, exceptionDetails: Protocol.Runtime.ExceptionDetails,
|
|
87
|
+
stackTrace: StackTrace.StackTrace.ParsedErrorStackTrace,
|
|
88
|
+
cause: SymbolizedError|null): Promise<SymbolizedErrorObject> {
|
|
88
89
|
const {exception, scriptId, lineNumber, columnNumber} = exceptionDetails;
|
|
89
90
|
if (!exception || exception.subtype !== 'error' || exception.className !== 'SyntaxError') {
|
|
90
|
-
throw new Error('
|
|
91
|
+
throw new Error('SymbolizedErrorObject.createForSyntaxError expects a SyntaxError');
|
|
91
92
|
}
|
|
93
|
+
|
|
94
|
+
const symbolizedError = new SymbolizedErrorObject(message, stackTrace, cause);
|
|
95
|
+
|
|
92
96
|
if (!scriptId) {
|
|
93
|
-
return
|
|
97
|
+
return symbolizedError;
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
100
|
+
const topFrame = exceptionDetails.stackTrace?.callFrames[0];
|
|
101
|
+
const isProgrammaticThrow = topFrame && topFrame.scriptId === scriptId && topFrame.lineNumber === lineNumber &&
|
|
102
|
+
topFrame.columnNumber === columnNumber;
|
|
103
|
+
|
|
104
|
+
if (!isProgrammaticThrow) {
|
|
105
|
+
const debuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
|
|
106
|
+
if (debuggerModel) {
|
|
107
|
+
const rawLocation = debuggerModel.createRawLocationByScriptId(scriptId, lineNumber, columnNumber);
|
|
108
|
+
// We don't implement dispose here. We won't create many of these so a couple
|
|
109
|
+
// LiveLocationPools and SymbolizedErrorObject instances leaking is fine.
|
|
110
|
+
await debuggerWorkspaceBinding.createLiveLocation(
|
|
111
|
+
rawLocation, symbolizedError.#updateSyntaxErrorLocation.bind(symbolizedError), new LiveLocationPool());
|
|
112
|
+
}
|
|
99
113
|
}
|
|
100
114
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// We don't implement dispose here. We won't create many of these so a couple
|
|
105
|
-
// LiveLocationPools and SymbolizedSyntaxError instances leaking is fine.
|
|
106
|
-
await debuggerWorkspaceBinding.createLiveLocation(
|
|
107
|
-
rawLocation, symbolizedSyntaxError.#update.bind(symbolizedSyntaxError), new LiveLocationPool());
|
|
115
|
+
return symbolizedError;
|
|
116
|
+
}
|
|
108
117
|
|
|
109
|
-
|
|
118
|
+
async #updateSyntaxErrorLocation(liveLocation: LiveLocation): Promise<void> {
|
|
119
|
+
this.#syntaxErrorLocation = await liveLocation.uiLocation();
|
|
120
|
+
this.dispatchEventToListeners(Events.UPDATED);
|
|
110
121
|
}
|
|
111
122
|
|
|
112
|
-
|
|
113
|
-
this.#uiLocation = await liveLocation.uiLocation();
|
|
123
|
+
#fireUpdated(): void {
|
|
114
124
|
this.dispatchEventToListeners(Events.UPDATED);
|
|
115
125
|
}
|
|
116
126
|
}
|
|
@@ -1067,6 +1067,46 @@ self.injectedExtensionAPI = function(
|
|
|
1067
1067
|
return typeof lastArgument === 'function' ? lastArgument as (...args: unknown[]) => unknown : undefined;
|
|
1068
1068
|
}
|
|
1069
1069
|
|
|
1070
|
+
/**
|
|
1071
|
+
* Helper to support both callback and Promise-based APIs.
|
|
1072
|
+
*
|
|
1073
|
+
* @param args The arguments object of the calling function.
|
|
1074
|
+
* @returns An object containing either the `callback` function, or the
|
|
1075
|
+
* `promise` and its `resolve`/`reject` functions.
|
|
1076
|
+
*/
|
|
1077
|
+
function callbackOrPromise<ResolveT, CallbackArgsT extends unknown[] = [ResolveT]>(args: IArguments): {
|
|
1078
|
+
callback?: (...args: CallbackArgsT) => void,
|
|
1079
|
+
promise?: Promise<ResolveT>,
|
|
1080
|
+
resolve?: (value: ResolveT) => void,
|
|
1081
|
+
reject?: (error: unknown) => void,
|
|
1082
|
+
} {
|
|
1083
|
+
const callback = extractCallbackArgument(args);
|
|
1084
|
+
if (callback) {
|
|
1085
|
+
return {callback: callback as (...args: CallbackArgsT) => void};
|
|
1086
|
+
}
|
|
1087
|
+
const {promise, resolve, reject} = Promise.withResolvers<ResolveT>();
|
|
1088
|
+
return {promise, resolve, reject};
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* Checks if the `response` from the ExtensionServer indicates an error. If an
|
|
1093
|
+
* error occurred and a `Promise` `reject` function is provided, this function
|
|
1094
|
+
* will reject the promise with a generic 'DevTools API encountered an error' Error.
|
|
1095
|
+
*
|
|
1096
|
+
* @param response The response object from the ExtensionServer.
|
|
1097
|
+
* @param reject The promise reject function, if applicable.
|
|
1098
|
+
* @returns `true` if an error occurred and the promise was rejected, `false`
|
|
1099
|
+
* otherwise.
|
|
1100
|
+
*/
|
|
1101
|
+
function checkErrorAndReject(response: unknown, reject?: (error: Error) => void): boolean {
|
|
1102
|
+
const res = response as {isError?: boolean, description?: string, details?: unknown[]};
|
|
1103
|
+
if (res.isError && reject) {
|
|
1104
|
+
reject(new Error('DevTools API encountered an error'));
|
|
1105
|
+
return true;
|
|
1106
|
+
}
|
|
1107
|
+
return false;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1070
1110
|
const LanguageServicesAPI = declareInterfaceClass(LanguageServicesAPIImpl);
|
|
1071
1111
|
const RecorderServicesAPI = declareInterfaceClass(RecorderServicesAPIImpl);
|
|
1072
1112
|
const Performance = declareInterfaceClass(PerformanceImpl);
|
|
@@ -1247,43 +1287,68 @@ self.injectedExtensionAPI = function(
|
|
|
1247
1287
|
extensionServer.sendRequest({command: PrivateAPI.Commands.Reload, options});
|
|
1248
1288
|
},
|
|
1249
1289
|
|
|
1250
|
-
eval: function(
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1290
|
+
eval: function<E = unknown>(this: PublicAPI.Chrome.DevTools.InspectedWindow, expression: string,
|
|
1291
|
+
optionsOrCallback?: unknown,
|
|
1292
|
+
_callback?: (result: unknown, exceptionInfo: object) => void): Promise<E>|
|
|
1293
|
+
void {
|
|
1294
|
+
const options = (typeof optionsOrCallback === 'object' && optionsOrCallback !== null) ?
|
|
1295
|
+
optionsOrCallback as PrivateAPI.EvaluateOptions :
|
|
1296
|
+
undefined;
|
|
1297
|
+
|
|
1298
|
+
const {callback: callbackArg, promise, resolve, reject} = callbackOrPromise<E, [unknown, object?]>(arguments);
|
|
1299
|
+
|
|
1256
1300
|
function callbackWrapper(result: unknown): void {
|
|
1257
|
-
|
|
1258
|
-
|
|
1301
|
+
if (checkErrorAndReject(result, reject)) {
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
const res = result as {
|
|
1306
|
+
value?: unknown,
|
|
1259
1307
|
isError?: boolean,
|
|
1260
1308
|
isException?: boolean,
|
|
1261
1309
|
};
|
|
1262
|
-
|
|
1263
|
-
|
|
1310
|
+
|
|
1311
|
+
if (res.isException) {
|
|
1312
|
+
reject?.(res);
|
|
1313
|
+
} else {
|
|
1314
|
+
resolve?.(res.value as E);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
if (res.isError || res.isException) {
|
|
1318
|
+
callbackArg?.(undefined, res);
|
|
1264
1319
|
} else {
|
|
1265
|
-
|
|
1320
|
+
callbackArg?.(res.value);
|
|
1266
1321
|
}
|
|
1267
1322
|
}
|
|
1268
1323
|
extensionServer.sendRequest(
|
|
1269
|
-
{
|
|
1270
|
-
|
|
1271
|
-
expression,
|
|
1272
|
-
evaluateOptions: (typeof evaluateOptions === 'object' ? evaluateOptions : undefined),
|
|
1273
|
-
},
|
|
1274
|
-
callback && callbackWrapper);
|
|
1275
|
-
return null;
|
|
1276
|
-
},
|
|
1324
|
+
{command: PrivateAPI.Commands.EvaluateOnInspectedPage, expression, evaluateOptions: options},
|
|
1325
|
+
callbackWrapper);
|
|
1277
1326
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1327
|
+
return promise;
|
|
1328
|
+
} as PublicAPI.Chrome.DevTools.InspectedWindow['eval'],
|
|
1329
|
+
|
|
1330
|
+
getResources: function(this: PublicAPI.Chrome.DevTools.InspectedWindow,
|
|
1331
|
+
_callback?: (resources: PublicAPI.Chrome.DevTools.Resource[]) => void):
|
|
1332
|
+
Promise<PublicAPI.Chrome.DevTools.Resource[]>|
|
|
1333
|
+
void {
|
|
1334
|
+
const {callback: callbackArg, promise, resolve, reject} =
|
|
1335
|
+
callbackOrPromise<PublicAPI.Chrome.DevTools.Resource[]>(arguments);
|
|
1336
|
+
|
|
1337
|
+
function callbackWrapper(response: unknown): void {
|
|
1338
|
+
if (checkErrorAndReject(response, reject)) {
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
const wrappedResources =
|
|
1343
|
+
((response || []) as APIImpl.ResourceData[]).map(r => new (Constructor(Resource))(r));
|
|
1344
|
+
resolve?.(wrappedResources);
|
|
1345
|
+
callbackArg?.(wrappedResources);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
extensionServer.sendRequest({command: PrivateAPI.Commands.GetPageResources}, callbackWrapper);
|
|
1349
|
+
|
|
1350
|
+
return promise;
|
|
1351
|
+
} as PublicAPI.Chrome.DevTools.InspectedWindow['getResources'],
|
|
1287
1352
|
};
|
|
1288
1353
|
|
|
1289
1354
|
function ResourceImpl(this: APIImpl.Resource, resourceData: APIImpl.ResourceData): void {
|
|
@@ -1292,9 +1357,9 @@ self.injectedExtensionAPI = function(
|
|
|
1292
1357
|
this._buildId = resourceData.buildId;
|
|
1293
1358
|
}
|
|
1294
1359
|
|
|
1295
|
-
(ResourceImpl.prototype as
|
|
1296
|
-
|
|
1297
|
-
|
|
1360
|
+
(ResourceImpl.prototype as
|
|
1361
|
+
Pick<APIImpl.Resource,
|
|
1362
|
+
'url'|'type'|'buildId'|'getContent'|'setContent'|'setFunctionRangesForScript'|'attachSourceMapURL'>) = {
|
|
1298
1363
|
get url(): string {
|
|
1299
1364
|
return (this as APIImpl.Resource)._url;
|
|
1300
1365
|
},
|
|
@@ -1307,25 +1372,51 @@ self.injectedExtensionAPI = function(
|
|
|
1307
1372
|
return (this as APIImpl.Resource)._buildId;
|
|
1308
1373
|
},
|
|
1309
1374
|
|
|
1310
|
-
getContent: function(this: APIImpl.Resource,
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1375
|
+
getContent: function(this: APIImpl.Resource, _callback?: (content: string, encoding: string) => void): Promise<{
|
|
1376
|
+
content: string, encoding: string,
|
|
1377
|
+
}>|
|
|
1378
|
+
void {
|
|
1379
|
+
const {callback: callbackArg, promise, resolve, reject} =
|
|
1380
|
+
callbackOrPromise<{content: string, encoding: string}, [string, string]>(arguments);
|
|
1315
1381
|
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1382
|
+
function callbackWrapper(response: unknown): void {
|
|
1383
|
+
if (checkErrorAndReject(response, reject)) {
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1319
1386
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1387
|
+
const {content, encoding} = response as {content: string, encoding: string};
|
|
1388
|
+
resolve?.({content, encoding});
|
|
1389
|
+
callbackArg?.(content, encoding);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
extensionServer.sendRequest({command: PrivateAPI.Commands.GetResourceContent, url: this._url},
|
|
1393
|
+
callbackWrapper);
|
|
1394
|
+
|
|
1395
|
+
return promise;
|
|
1396
|
+
} as PublicAPI.Chrome.DevTools.Resource['getContent'],
|
|
1397
|
+
|
|
1398
|
+
setContent: function(this: APIImpl.Resource, content: string, commit: boolean,
|
|
1399
|
+
_callback?: (status?: object) => void): Promise<void>|
|
|
1400
|
+
void {
|
|
1401
|
+
const {callback: callbackArg, promise, resolve, reject} = callbackOrPromise<void, [object]>(arguments);
|
|
1402
|
+
|
|
1403
|
+
function callbackWrapper(response: unknown): void {
|
|
1404
|
+
if (checkErrorAndReject(response, reject)) {
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
resolve?.();
|
|
1409
|
+
callbackArg?.(response as object);
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
extensionServer.sendRequest(
|
|
1413
|
+
{command: PrivateAPI.Commands.SetResourceContent, url: this._url, content, commit}, callbackWrapper);
|
|
1414
|
+
|
|
1415
|
+
return promise;
|
|
1416
|
+
} as PublicAPI.Chrome.DevTools.Resource['setContent'],
|
|
1326
1417
|
|
|
1327
|
-
setFunctionRangesForScript: function(
|
|
1328
|
-
|
|
1418
|
+
setFunctionRangesForScript: function(this: APIImpl.Resource,
|
|
1419
|
+
ranges: PublicAPI.Chrome.DevTools.NamedFunctionRange[]): Promise<void> {
|
|
1329
1420
|
return new Promise(
|
|
1330
1421
|
(resolve, reject) => extensionServer.sendRequest(
|
|
1331
1422
|
{
|
|
@@ -40,6 +40,7 @@ export class Importer {
|
|
|
40
40
|
}
|
|
41
41
|
const request = SDK.NetworkRequest.NetworkRequest.createWithoutBackendRequest(
|
|
42
42
|
'har-' + requests.length, entry.request.url, documentURL, initiator);
|
|
43
|
+
request.setIsImportedHar(true);
|
|
43
44
|
const page = pageref ? pages.get(pageref) : undefined;
|
|
44
45
|
if (!pageLoad && pageref && page) {
|
|
45
46
|
pageLoad = Importer.buildPageLoad(page, request);
|
|
@@ -203,7 +203,14 @@ function createFunctionCode(
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
/**
|
|
206
|
-
*
|
|
206
|
+
* Resolves the function code and its surrounding context for a given location.
|
|
207
|
+
*
|
|
208
|
+
* The input location (line, column) may be either an authored (source-mapped)
|
|
209
|
+
* location or a raw location. The function will attempt to resolve it to a
|
|
210
|
+
* raw location regardless. This is necessary because callers (such as AI
|
|
211
|
+
* assistance) may work with either format.
|
|
212
|
+
*
|
|
213
|
+
* We filter projects by `target` to prevent cross-origin leaks.
|
|
207
214
|
*/
|
|
208
215
|
export async function getFunctionCodeFromLocation(
|
|
209
216
|
target: SDK.Target.Target, url: Platform.DevToolsPath.UrlString, line: number, column: number,
|
|
@@ -213,10 +220,13 @@ export async function getFunctionCodeFromLocation(
|
|
|
213
220
|
throw new Error('missing debugger model');
|
|
214
221
|
}
|
|
215
222
|
|
|
216
|
-
let uiSourceCode;
|
|
223
|
+
let uiSourceCode: Workspace.UISourceCode.UISourceCode|null = null;
|
|
217
224
|
const debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
|
|
218
225
|
const projects = debuggerWorkspaceBinding.workspace.projectsForType(Workspace.Workspace.projectTypes.Network);
|
|
219
226
|
for (const project of projects) {
|
|
227
|
+
if (Bindings.NetworkProject.NetworkProject.getTargetForProject(project) !== target) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
220
230
|
uiSourceCode = project.uiSourceCodeForURL(url);
|
|
221
231
|
if (uiSourceCode) {
|
|
222
232
|
break;
|