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.
Files changed (45) hide show
  1. package/eslint.config.mjs +3 -1
  2. package/extension-api/ExtensionAPI.d.ts +83 -12
  3. package/front_end/core/host/UserMetrics.ts +0 -1
  4. package/front_end/core/root/ExperimentNames.ts +0 -1
  5. package/front_end/core/sdk/ConsoleModel.ts +4 -0
  6. package/front_end/core/sdk/NetworkRequest.ts +12 -0
  7. package/front_end/core/sdk/SourceMap.ts +15 -18
  8. package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -2
  9. package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -2
  10. package/front_end/entrypoints/main/MainImpl.ts +0 -6
  11. package/front_end/models/ai_assistance/AiAgent2.ts +1 -0
  12. package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +22 -16
  13. package/front_end/models/ai_assistance/agents/AiAgent.ts +19 -6
  14. package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +5 -5
  15. package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +1 -94
  16. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +25 -0
  17. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +22 -0
  18. package/front_end/models/ai_assistance/agents/StorageAgent.ts +54 -1
  19. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +1 -2
  20. package/front_end/models/ai_assistance/agents/StylingAgent.ts +5 -0
  21. package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +4 -10
  22. package/front_end/models/ai_assistance/tools/Tool.ts +6 -0
  23. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +6 -9
  24. package/front_end/models/bindings/DefaultScriptMapping.ts +2 -1
  25. package/front_end/models/bindings/SymbolizedError.ts +45 -35
  26. package/front_end/models/extensions/ExtensionAPI.ts +138 -47
  27. package/front_end/models/har/Importer.ts +1 -0
  28. package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +12 -2
  29. package/front_end/models/stack_trace/DetailedErrorStackParser.ts +44 -51
  30. package/front_end/models/stack_trace/StackTrace.ts +7 -0
  31. package/front_end/models/stack_trace/StackTraceImpl.ts +13 -4
  32. package/front_end/models/stack_trace/StackTraceModel.ts +9 -8
  33. package/front_end/panels/accessibility/AccessibilitySidebarView.ts +2 -1
  34. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +2 -1
  35. package/front_end/panels/application/ApplicationPanelSidebar.ts +39 -0
  36. package/front_end/panels/application/ApplicationPanelTreeElement.ts +39 -0
  37. package/front_end/panels/application/CookieItemsView.ts +2 -2
  38. package/front_end/panels/application/resourcesSidebar.css +11 -0
  39. package/front_end/panels/console/SymbolizedErrorWidget.ts +10 -7
  40. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -0
  41. package/front_end/panels/sources/SourcesPanel.ts +2 -1
  42. package/front_end/ui/legacy/StackedPane.ts +229 -0
  43. package/front_end/ui/legacy/ViewManager.ts +59 -169
  44. package/front_end/ui/legacy/legacy.ts +3 -1
  45. 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 activeContext = context.conversationContext;
112
- if (!activeContext || !(activeContext instanceof DOMNodeContext)) {
113
- return {error: 'Error: Could not find the currently selected element.'};
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: () => selectedNode,
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
- this.#project.addUISourceCodeWithProvider(uiSourceCode, script, null, 'text/javascript');
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|SymbolizedSyntaxError|UnparsableError;
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
- #fireUpdated(): void {
68
- this.dispatchEventToListeners(Events.UPDATED);
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
- get uiLocation(): Workspace.UISourceCode.UILocation|null {
82
- return this.#uiLocation;
83
- }
84
-
85
- static async fromExceptionDetails(
86
- target: SDK.Target.Target, debuggerWorkspaceBinding: DebuggerWorkspaceBinding,
87
- exceptionDetails: Protocol.Runtime.ExceptionDetails): Promise<SymbolizedSyntaxError|null> {
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('SymbolizedSyntaxError.fromExceptionDetails expects a SyntaxError');
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 null;
97
+ return symbolizedError;
94
98
  }
95
99
 
96
- const debuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
97
- if (!debuggerModel) {
98
- return null;
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
- const rawLocation = debuggerModel.createRawLocationByScriptId(scriptId, lineNumber, columnNumber);
102
- const symbolizedSyntaxError = new SymbolizedSyntaxError(exception.description || '');
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
- return symbolizedSyntaxError;
118
+ async #updateSyntaxErrorLocation(liveLocation: LiveLocation): Promise<void> {
119
+ this.#syntaxErrorLocation = await liveLocation.uiLocation();
120
+ this.dispatchEventToListeners(Events.UPDATED);
110
121
  }
111
122
 
112
- async #update(liveLocation: LiveLocation): Promise<void> {
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
- expression: string,
1252
- evaluateOptions: {scriptExecutionContext?: string, frameURL?: string, useContentScriptContext?: boolean}):
1253
- Object |
1254
- null {
1255
- const callback = extractCallbackArgument(arguments);
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
- const {isError, isException, value} = result as {
1258
- value: unknown,
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
- if (isError || isException) {
1263
- callback?.(undefined, result);
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
- callback?.(value);
1320
+ callbackArg?.(res.value);
1266
1321
  }
1267
1322
  }
1268
1323
  extensionServer.sendRequest(
1269
- {
1270
- command: PrivateAPI.Commands.EvaluateOnInspectedPage,
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
- getResources: function(callback?: (resources: PublicAPI.Chrome.DevTools.Resource[]) => unknown): void {
1279
- function wrapResource(resourceData: APIImpl.ResourceData): APIImpl.Resource {
1280
- return new (Constructor(Resource))(resourceData);
1281
- }
1282
- function callbackWrapper(resources: unknown): void {
1283
- callback?.((resources as APIImpl.ResourceData[]).map(wrapResource));
1284
- }
1285
- extensionServer.sendRequest({command: PrivateAPI.Commands.GetPageResources}, callback && callbackWrapper);
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 Pick<
1296
- APIImpl.Resource,
1297
- 'url'|'type'|'buildId'|'getContent'|'setContent'|'setFunctionRangesForScript'|'attachSourceMapURL'>) = {
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, callback?: (content: string, encoding: string) => unknown): void {
1311
- function callbackWrapper(response: unknown): void {
1312
- const {content, encoding} = response as {content: string, encoding: string};
1313
- callback?.(content, encoding);
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
- extensionServer.sendRequest(
1317
- {command: PrivateAPI.Commands.GetResourceContent, url: this._url}, callback && callbackWrapper);
1318
- },
1382
+ function callbackWrapper(response: unknown): void {
1383
+ if (checkErrorAndReject(response, reject)) {
1384
+ return;
1385
+ }
1319
1386
 
1320
- setContent: function(
1321
- this: APIImpl.Resource, content: string, commit: boolean, callback: (error?: Object) => unknown): void {
1322
- extensionServer.sendRequest(
1323
- {command: PrivateAPI.Commands.SetResourceContent, url: this._url, content, commit},
1324
- callback as (response: unknown) => unknown);
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
- this: APIImpl.Resource, ranges: PublicAPI.Chrome.DevTools.NamedFunctionRange[]): Promise<void> {
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
- * The input location may be a source mapped location or a raw location.
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;