chrome-devtools-frontend 1.0.1521880 → 1.0.1522585

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 (59) hide show
  1. package/docs/ui_engineering.md +76 -0
  2. package/front_end/core/host/GdpClient.ts +116 -66
  3. package/front_end/core/root/Runtime.ts +1 -0
  4. package/front_end/core/sdk/EnhancedTracesParser.ts +13 -6
  5. package/front_end/entrypoints/inspector_main/InspectorMain.ts +82 -32
  6. package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +1 -1
  7. package/front_end/entrypoints/main/MainImpl.ts +7 -1
  8. package/front_end/generated/Deprecation.ts +4 -4
  9. package/front_end/models/ai_assistance/agents/NetworkAgent.ts +10 -6
  10. package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +559 -0
  11. package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +42 -4
  12. package/front_end/models/badges/UserBadges.ts +14 -16
  13. package/front_end/models/javascript_metadata/NativeFunctions.js +1 -1
  14. package/front_end/models/trace/LanternComputationData.ts +1 -0
  15. package/front_end/models/trace/handlers/NetworkRequestsHandler.ts +10 -0
  16. package/front_end/models/trace/insights/DocumentLatency.ts +9 -10
  17. package/front_end/models/trace/types/TraceEvents.ts +6 -5
  18. package/front_end/panels/ai_assistance/components/UserActionRow.ts +1 -2
  19. package/front_end/panels/application/IndexedDBViews.ts +1 -0
  20. package/front_end/panels/application/ReportingApiTreeElement.ts +1 -2
  21. package/front_end/panels/application/ReportingApiView.ts +18 -20
  22. package/front_end/panels/application/ServiceWorkerCacheViews.ts +3 -0
  23. package/front_end/panels/application/components/EndpointsGrid.ts +51 -59
  24. package/front_end/panels/application/components/ReportsGrid.ts +86 -107
  25. package/front_end/panels/application/components/StorageMetadataView.ts +30 -4
  26. package/front_end/panels/application/components/endpointsGrid.css +30 -0
  27. package/front_end/panels/application/components/reportsGrid.css +34 -0
  28. package/front_end/panels/application/components/storageMetadataView.css +9 -0
  29. package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +19 -27
  30. package/front_end/panels/common/BadgeNotification.ts +10 -3
  31. package/front_end/panels/network/NetworkPanel.ts +1 -1
  32. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +31 -32
  33. package/front_end/panels/search/SearchResultsPane.ts +14 -13
  34. package/front_end/panels/search/SearchView.ts +3 -20
  35. package/front_end/panels/settings/components/SyncSection.ts +8 -6
  36. package/front_end/panels/sources/SearchSourcesView.ts +1 -1
  37. package/front_end/panels/timeline/TimelineFlameChartView.ts +17 -0
  38. package/front_end/panels/timeline/TimelinePanel.ts +5 -0
  39. package/front_end/panels/timeline/TimelineUIUtils.ts +12 -3
  40. package/front_end/panels/timeline/components/ExportTraceOptions.ts +21 -9
  41. package/front_end/panels/timeline/timelineDetailsView.css +5 -0
  42. package/front_end/panels/whats_new/ReleaseNoteText.ts +15 -11
  43. package/front_end/panels/whats_new/resources/WNDT.md +9 -6
  44. package/front_end/third_party/chromium/README.chromium +1 -1
  45. package/front_end/third_party/diff/README.chromium +0 -1
  46. package/front_end/ui/components/tooltips/Tooltip.ts +13 -4
  47. package/front_end/ui/legacy/Treeoutline.ts +6 -9
  48. package/front_end/ui/legacy/UIUtils.ts +4 -17
  49. package/front_end/ui/legacy/Widget.ts +0 -5
  50. package/front_end/ui/legacy/XElement.ts +0 -33
  51. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +3 -3
  52. package/front_end/ui/legacy/components/perf_ui/FilmStripView.ts +38 -21
  53. package/front_end/ui/legacy/components/perf_ui/filmStripView.css +29 -0
  54. package/front_end/ui/legacy/components/source_frame/XMLView.ts +3 -2
  55. package/front_end/ui/legacy/legacy.ts +0 -2
  56. package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
  57. package/package.json +1 -1
  58. package/front_end/panels/application/components/reportingApiGrid.css +0 -31
  59. package/front_end/ui/legacy/XWidget.ts +0 -133
@@ -0,0 +1,559 @@
1
+ Title: StylingAgent describeElement should describe an element with no children, siblings, or parent
2
+ Content:
3
+ * Its selector is `div#myElement`
4
+ === end content
5
+
6
+ Title: StylingAgent describeElement should describe an element with child element and text nodes
7
+ Content:
8
+ * Its selector is `div#parentElement`
9
+ * It has 2 child element nodes: `span.child1`, `span.child2`
10
+ * It only has 1 child text node
11
+ === end content
12
+
13
+ Title: StylingAgent describeElement should describe an element with siblings and a parent
14
+ Content:
15
+ * Its selector is `div#parentElement`
16
+ * It has a next sibling and it is an element node
17
+ * It has a previous sibling and it is a non element node
18
+ * Its parent's selector is `div#grandparentElement`
19
+ * Its parent is a non element node
20
+ * Its parent has only 1 child element node
21
+ * Its parent has only 1 child text node
22
+ === end content
23
+
24
+ Title: StylingAgent buildRequest structure matches the snapshot
25
+ Content:
26
+ {
27
+ "client": "CHROME_DEVTOOLS",
28
+ "current_message": {
29
+ "parts": [
30
+ {
31
+ "text": "test input"
32
+ }
33
+ ],
34
+ "role": 1
35
+ },
36
+ "historical_contexts": [
37
+ {
38
+ "parts": [
39
+ {
40
+ "text": "QUERY: question"
41
+ }
42
+ ],
43
+ "role": 1
44
+ },
45
+ {
46
+ "parts": [
47
+ {
48
+ "text": "answer"
49
+ }
50
+ ],
51
+ "role": 2
52
+ }
53
+ ],
54
+ "function_declarations": [
55
+ {
56
+ "name": "executeJavaScript",
57
+ "description": "This function allows you to run JavaScript code on the inspected page to access the element styles and page content.\nCall this function to gather additional information or modify the page state. Call this function enough times to investigate the user request.",
58
+ "parameters": {
59
+ "type": 6,
60
+ "description": "",
61
+ "nullable": false,
62
+ "properties": {
63
+ "code": {
64
+ "type": 1,
65
+ "description": "JavaScript code snippet to run on the inspected page. Make sure the code is formatted for readability.\n\n# Instructions\n\n* To return data, define a top-level `data` variable and populate it with data you want to get. Only JSON-serializable objects can be assigned to `data`.\n* If you modify styles on an element, ALWAYS call the pre-defined global `async setElementStyles(el: Element, styles: object)` function. This function is an internal mechanism for you and should never be presented as a command/advice to the user.\n* Use `window.getComputedStyle` to gather **computed** styles and make sure that you take the distinction between authored styles and computed styles into account.\n* **CRITICAL** Only get styles that might be relevant to the user request.\n* **CRITICAL** Call `window.getComputedStyle` only once per element and store results into a local variable. Never try to return all the styles of the element in `data`.\n* **CRITICAL** Never assume a selector for the elements unless you verified your knowledge.\n* **CRITICAL** Consider that `data` variable from the previous function calls are not available in a new function call.\n\nFor example, the code to return basic styles:\n\n```\nconst styles = window.getComputedStyle($0);\nconst data = {\n display: styles['display'],\n visibility: styles['visibility'],\n position: styles['position'],\n left: styles['right'],\n top: styles['top'],\n width: styles['width'],\n height: styles['height'],\n zIndex: styles['z-index']\n};\n```\n\nFor example, the code to change element styles:\n\n```\nawait setElementStyles($0, {\n color: 'blue',\n});\n```\n\nFor example, the code to get current and parent styles at once:\n\n```\nconst styles = window.getComputedStyle($0);\nconst parentStyles = window.getComputedStyle($0.parentElement);\nconst data = {\n currentElementStyles: {\n display: styles['display'],\n visibility: styles['visibility'],\n position: styles['position'],\n left: styles['right'],\n top: styles['top'],\n width: styles['width'],\n height: styles['height'],\n zIndex: styles['z-index'],\n },\n parentElementStyles: {\n display: parentStyles['display'],\n visibility: parentStyles['visibility'],\n position: parentStyles['position'],\n left: parentStyles['right'],\n top: parentStyles['top'],\n width: parentStyles['width'],\n height: parentStyles['height'],\n zIndex: parentStyles['z-index'],\n },\n};\n```\n\nFor example, the code to get check siblings and overlapping elements:\n\n```\nconst computedStyles = window.getComputedStyle($0);\nconst parentComputedStyles = window.getComputedStyle($0.parentElement);\nconst data = {\n numberOfChildren: $0.children.length,\n numberOfSiblings: $0.parentElement.children.length,\n hasPreviousSibling: !!$0.previousElementSibling,\n hasNextSibling: !!$0.nextElementSibling,\n elementStyles: {\n display: computedStyles['display'],\n visibility: computedStyles['visibility'],\n position: computedStyles['position'],\n clipPath: computedStyles['clip-path'],\n zIndex: computedStyles['z-index']\n },\n parentStyles: {\n display: parentComputedStyles['display'],\n visibility: parentComputedStyles['visibility'],\n position: parentComputedStyles['position'],\n clipPath: parentComputedStyles['clip-path'],\n zIndex: parentComputedStyles['z-index']\n },\n overlappingElements: Array.from(document.querySelectorAll('*'))\n .filter(el => {\n const rect = el.getBoundingClientRect();\n const popupRect = $0.getBoundingClientRect();\n return (\n el !== $0 &&\n rect.left < popupRect.right &&\n rect.right > popupRect.left &&\n rect.top < popupRect.bottom &&\n rect.bottom > popupRect.top\n );\n })\n .map(el => ({\n tagName: el.tagName,\n id: el.id,\n className: el.className,\n zIndex: window.getComputedStyle(el)['z-index']\n }))\n};\n```\n"
66
+ },
67
+ "thought": {
68
+ "type": 1,
69
+ "description": "Explain why you want to run this code"
70
+ },
71
+ "title": {
72
+ "type": 1,
73
+ "description": "Provide a summary of what the code does. For example, \"Checking related element styles\"."
74
+ }
75
+ }
76
+ }
77
+ }
78
+ ],
79
+ "options": {
80
+ "model_id": "test model"
81
+ },
82
+ "metadata": {
83
+ "disable_user_content_logging": false,
84
+ "string_session_id": "sessionId",
85
+ "user_tier": 2,
86
+ "client_version": "unit_test+function_calling"
87
+ },
88
+ "functionality_type": 5,
89
+ "client_feature": 2
90
+ }
91
+ === end content
92
+
93
+ Title: StylingAgent buildRequest builds a request with aborted query in history before a real request
94
+ Content:
95
+ [
96
+ {
97
+ "parts": [
98
+ {
99
+ "text": "# Inspected element\n\nelement-description\n\n# User request\n\nQUERY: test2"
100
+ }
101
+ ],
102
+ "role": 1
103
+ },
104
+ {
105
+ "parts": [
106
+ {
107
+ "functionCall": {
108
+ "name": "executeJavaScript",
109
+ "args": {
110
+ "title": "title2",
111
+ "thought": "thought2",
112
+ "code": "action2"
113
+ }
114
+ }
115
+ }
116
+ ],
117
+ "role": 2
118
+ },
119
+ {
120
+ "parts": [
121
+ {
122
+ "functionResponse": {
123
+ "name": "executeJavaScript",
124
+ "response": {
125
+ "result": "result2"
126
+ }
127
+ }
128
+ }
129
+ ],
130
+ "role": 0
131
+ },
132
+ {
133
+ "parts": [
134
+ {
135
+ "text": "answer2"
136
+ }
137
+ ],
138
+ "role": 2
139
+ }
140
+ ]
141
+ === end content
142
+
143
+ Title: StylingAgent run generates an answer immediately
144
+ Content:
145
+ [
146
+ {
147
+ "type": "user-query",
148
+ "query": "test"
149
+ },
150
+ {
151
+ "type": "context",
152
+ "title": "Analyzing the prompt",
153
+ "details": [
154
+ {
155
+ "title": "Data used",
156
+ "text": "* Its selector is `undefined`"
157
+ }
158
+ ]
159
+ },
160
+ {
161
+ "type": "querying"
162
+ },
163
+ {
164
+ "type": "answer",
165
+ "text": "this is the answer",
166
+ "complete": true
167
+ }
168
+ ]
169
+ === end content
170
+
171
+ Title: StylingAgent run generates an answer immediately with correct historical contexts in the new request
172
+ Content:
173
+ [
174
+ {
175
+ "parts": [
176
+ {
177
+ "text": "# Inspected element\n\n* Its selector is `undefined`\n\n# User request\n\nQUERY: test"
178
+ }
179
+ ],
180
+ "role": 1
181
+ },
182
+ {
183
+ "parts": [
184
+ {
185
+ "text": "this is the answer"
186
+ }
187
+ ],
188
+ "role": 2
189
+ }
190
+ ]
191
+ === end content
192
+
193
+ Title: StylingAgent run correctly handles historical_contexts in AIDA requests
194
+ Content:
195
+ [
196
+ {
197
+ "text": "# Inspected element\n\n* Its selector is `undefined`\n\n# User request\n\nQUERY: test"
198
+ },
199
+ [
200
+ {
201
+ "parts": [
202
+ {
203
+ "text": "# Inspected element\n\n* Its selector is `undefined`\n\n# User request\n\nQUERY: test"
204
+ }
205
+ ],
206
+ "role": 1
207
+ },
208
+ {
209
+ "parts": [
210
+ {
211
+ "functionCall": {
212
+ "name": "executeJavaScript",
213
+ "args": {
214
+ "code": "const data = {\"test\": \"observation\"}",
215
+ "thought": "I am thinking.",
216
+ "title": "thinking"
217
+ }
218
+ }
219
+ }
220
+ ],
221
+ "role": 2
222
+ }
223
+ ]
224
+ ]
225
+ === end content
226
+
227
+ Title: StylingAgent run generates an rpcId for the answer
228
+ Content:
229
+ [
230
+ {
231
+ "type": "user-query",
232
+ "query": "test"
233
+ },
234
+ {
235
+ "type": "context",
236
+ "title": "Analyzing the prompt",
237
+ "details": [
238
+ {
239
+ "title": "Data used",
240
+ "text": "* Its selector is `undefined`"
241
+ }
242
+ ]
243
+ },
244
+ {
245
+ "type": "querying"
246
+ },
247
+ {
248
+ "type": "answer",
249
+ "text": "this is the answer",
250
+ "complete": true,
251
+ "rpcId": 123
252
+ }
253
+ ]
254
+ === end content
255
+
256
+ Title: StylingAgent run throws an error based on the attribution metadata including RecitationAction.BLOCK
257
+ Content:
258
+ [
259
+ {
260
+ "type": "user-query",
261
+ "query": "test"
262
+ },
263
+ {
264
+ "type": "context",
265
+ "title": "Analyzing the prompt",
266
+ "details": [
267
+ {
268
+ "title": "Data used",
269
+ "text": "* Its selector is `undefined`"
270
+ }
271
+ ]
272
+ },
273
+ {
274
+ "type": "querying"
275
+ },
276
+ {
277
+ "type": "answer",
278
+ "text": "this is the partial answer",
279
+ "complete": false
280
+ },
281
+ {
282
+ "type": "error",
283
+ "error": "block"
284
+ }
285
+ ]
286
+ === end content
287
+
288
+ Title: StylingAgent run does not throw an error based on attribution metadata not including RecitationAction.BLOCK
289
+ Content:
290
+ [
291
+ {
292
+ "type": "user-query",
293
+ "query": "test"
294
+ },
295
+ {
296
+ "type": "context",
297
+ "title": "Analyzing the prompt",
298
+ "details": [
299
+ {
300
+ "title": "Data used",
301
+ "text": "* Its selector is `undefined`"
302
+ }
303
+ ]
304
+ },
305
+ {
306
+ "type": "querying"
307
+ },
308
+ {
309
+ "type": "answer",
310
+ "text": "this is the answer",
311
+ "complete": true,
312
+ "rpcId": 123
313
+ }
314
+ ]
315
+ === end content
316
+
317
+ Title: StylingAgent run generates a response if nothing is returned
318
+ Content:
319
+ [
320
+ {
321
+ "type": "user-query",
322
+ "query": "test"
323
+ },
324
+ {
325
+ "type": "context",
326
+ "title": "Analyzing the prompt",
327
+ "details": [
328
+ {
329
+ "title": "Data used",
330
+ "text": "* Its selector is `undefined`"
331
+ }
332
+ ]
333
+ },
334
+ {
335
+ "type": "querying"
336
+ },
337
+ {
338
+ "type": "error",
339
+ "error": "unknown"
340
+ }
341
+ ]
342
+ === end content
343
+
344
+ Title: StylingAgent run generates an action response if action and answer both present
345
+ Content:
346
+ [
347
+ {
348
+ "type": "user-query",
349
+ "query": "test"
350
+ },
351
+ {
352
+ "type": "context",
353
+ "title": "Analyzing the prompt",
354
+ "details": [
355
+ {
356
+ "title": "Data used",
357
+ "text": "* Its selector is `undefined`"
358
+ }
359
+ ]
360
+ },
361
+ {
362
+ "type": "querying"
363
+ },
364
+ {
365
+ "type": "thought",
366
+ "thought": "I am thinking."
367
+ },
368
+ {
369
+ "type": "action",
370
+ "code": "console.log('hello');",
371
+ "output": "hello",
372
+ "canceled": false
373
+ },
374
+ {
375
+ "type": "querying"
376
+ },
377
+ {
378
+ "type": "answer",
379
+ "text": "this is the actual answer",
380
+ "complete": true
381
+ }
382
+ ]
383
+ === end content
384
+
385
+ Title: StylingAgent run generates history for multiple actions
386
+ Content:
387
+ [
388
+ {
389
+ "parts": [
390
+ {
391
+ "text": "# Inspected element\n\n* Its selector is `undefined`\n\n# User request\n\nQUERY: test"
392
+ }
393
+ ],
394
+ "role": 1
395
+ },
396
+ {
397
+ "parts": [
398
+ {
399
+ "functionCall": {
400
+ "name": "executeJavaScript",
401
+ "args": {
402
+ "thought": "thought 1",
403
+ "title": "test",
404
+ "code": "console.log('test')"
405
+ }
406
+ }
407
+ }
408
+ ],
409
+ "role": 2
410
+ },
411
+ {
412
+ "parts": [
413
+ {
414
+ "functionResponse": {
415
+ "name": "executeJavaScript",
416
+ "response": {
417
+ "result": "undefined"
418
+ }
419
+ }
420
+ }
421
+ ],
422
+ "role": 0
423
+ },
424
+ {
425
+ "parts": [
426
+ {
427
+ "functionCall": {
428
+ "name": "executeJavaScript",
429
+ "args": {
430
+ "thought": "thought 2",
431
+ "title": "test",
432
+ "code": "console.log('test')"
433
+ }
434
+ }
435
+ }
436
+ ],
437
+ "role": 2
438
+ },
439
+ {
440
+ "parts": [
441
+ {
442
+ "functionResponse": {
443
+ "name": "executeJavaScript",
444
+ "response": {
445
+ "result": "undefined"
446
+ }
447
+ }
448
+ }
449
+ ],
450
+ "role": 0
451
+ },
452
+ {
453
+ "parts": [
454
+ {
455
+ "functionCall": {
456
+ "name": "executeJavaScript",
457
+ "args": {
458
+ "thought": "thought 3",
459
+ "title": "test",
460
+ "code": "console.log('test')"
461
+ }
462
+ }
463
+ }
464
+ ],
465
+ "role": 2
466
+ },
467
+ {
468
+ "parts": [
469
+ {
470
+ "functionResponse": {
471
+ "name": "executeJavaScript",
472
+ "response": {
473
+ "result": "undefined"
474
+ }
475
+ }
476
+ }
477
+ ],
478
+ "role": 0
479
+ },
480
+ {
481
+ "parts": [
482
+ {
483
+ "text": "this is the answer"
484
+ }
485
+ ],
486
+ "role": 2
487
+ }
488
+ ]
489
+ === end content
490
+
491
+ Title: StylingAgent enhanceQuery does not add multimodal input evaluation prompt when multimodal is disabled
492
+ Content:
493
+ # Inspected element
494
+
495
+ * Its selector is `div#myElement`
496
+
497
+ # User request
498
+
499
+ QUERY: test query
500
+ === end content
501
+
502
+ Title: StylingAgent enhanceQuery does not add multimodal input evaluation prompt when multimodal is enabled but multimodalInputType is missing
503
+ Content:
504
+ # Inspected element
505
+
506
+ * Its selector is `div#myElement`
507
+
508
+ # User request
509
+
510
+ QUERY: test query
511
+ === end content
512
+
513
+ Title: StylingAgent enhanceQuery adds multimodal input evaluation prompt when multimodal is enabled and multimodalInputType is screenshot
514
+ Content:
515
+ The user has provided you a screenshot of the page (as visible in the viewport) in base64-encoded format. You SHOULD use it while answering user's queries.
516
+
517
+ * Try to connect the screenshot to actual DOM elements in the page.
518
+ # Considerations for evaluating image:
519
+ * Pay close attention to the spatial details as well as the visual appearance of the selected element in the image, particularly in relation to layout, spacing, and styling.
520
+ * Analyze the image to identify the layout structure surrounding the element, including the positioning of neighboring elements.
521
+ * Extract visual information from the image, such as colors, fonts, spacing, and sizes, that might be relevant to the user's query.
522
+ * If the image suggests responsiveness issues (e.g., cropped content, overlapping elements), consider those in your response.
523
+ * Consider the surrounding elements and overall layout in the image, but prioritize the selected element's styling and positioning.
524
+ * **CRITICAL** When the user provides image input, interpret and use content and information from the image STRICTLY for web site debugging purposes.
525
+
526
+ * As part of THOUGHT, evaluate the image to gather data that might be needed to answer the question.
527
+ In case query is related to the image, ALWAYS first use image evaluation to get all details from the image. ONLY after you have all data needed from image, you should move to other steps.
528
+
529
+ # Inspected element
530
+
531
+ * Its selector is `div#myElement`
532
+
533
+ # User request
534
+
535
+ QUERY: test query
536
+ === end content
537
+
538
+ Title: StylingAgent enhanceQuery adds multimodal input evaluation prompt when multimodal is enabled and multimodalInputType is uploaded image
539
+ Content:
540
+ The user has uploaded an image in base64-encoded format. You SHOULD use it while answering user's queries.
541
+ # Considerations for evaluating image:
542
+ * Pay close attention to the spatial details as well as the visual appearance of the selected element in the image, particularly in relation to layout, spacing, and styling.
543
+ * Analyze the image to identify the layout structure surrounding the element, including the positioning of neighboring elements.
544
+ * Extract visual information from the image, such as colors, fonts, spacing, and sizes, that might be relevant to the user's query.
545
+ * If the image suggests responsiveness issues (e.g., cropped content, overlapping elements), consider those in your response.
546
+ * Consider the surrounding elements and overall layout in the image, but prioritize the selected element's styling and positioning.
547
+ * **CRITICAL** When the user provides image input, interpret and use content and information from the image STRICTLY for web site debugging purposes.
548
+
549
+ * As part of THOUGHT, evaluate the image to gather data that might be needed to answer the question.
550
+ In case query is related to the image, ALWAYS first use image evaluation to get all details from the image. ONLY after you have all data needed from image, you should move to other steps.
551
+
552
+ # Inspected element
553
+
554
+ * Its selector is `div#myElement`
555
+
556
+ # User request
557
+
558
+ QUERY: test query
559
+ === end content
@@ -5,10 +5,12 @@
5
5
  import type * as SDK from '../../../core/sdk/sdk.js';
6
6
  import * as Logs from '../../logs/logs.js';
7
7
  import * as NetworkTimeCalculator from '../../network_time_calculator/network_time_calculator.js';
8
+ import * as TextUtils from '../../text_utils/text_utils.js';
8
9
 
9
10
  import {seconds} from './UnitFormatters.js';
10
11
 
11
12
  const MAX_HEADERS_SIZE = 1000;
13
+ const MAX_BODY_SIZE = 10000;
12
14
 
13
15
  /**
14
16
  * Sanitizes the set of headers, removing values that are not on the allow-list and replacing them with '<redacted>'.
@@ -24,6 +26,8 @@ function sanitizeHeaders(headers: Array<{name: string, value: string}>): Array<{
24
26
 
25
27
  export class NetworkRequestFormatter {
26
28
  #calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator;
29
+ #request: SDK.NetworkRequest.NetworkRequest;
30
+
27
31
  static allowHeader(headerName: string): boolean {
28
32
  return allowedHeaders.has(headerName.toLowerCase().trim());
29
33
  }
@@ -37,6 +41,31 @@ export class NetworkRequestFormatter {
37
41
  MAX_HEADERS_SIZE);
38
42
  }
39
43
 
44
+ static async formatBody(title: string, request: SDK.NetworkRequest.NetworkRequest, maxBodySize: number):
45
+ Promise<string> {
46
+ const data = await request.requestContentData();
47
+
48
+ if (TextUtils.ContentData.ContentData.isError(data)) {
49
+ return '';
50
+ }
51
+
52
+ if (data.isEmpty) {
53
+ return `${title}\n<empty response>`;
54
+ }
55
+
56
+ if (data.isTextContent) {
57
+ const dataAsText = data.text;
58
+
59
+ if (dataAsText.length > maxBodySize) {
60
+ return `${title}\n${dataAsText.substring(0, maxBodySize) + '... <truncated>'}`;
61
+ }
62
+
63
+ return `${title}\n${dataAsText}`;
64
+ }
65
+
66
+ return `${title}\n<binary data>`;
67
+ }
68
+
40
69
  static formatInitiatorUrl(initiatorUrl: string, allowedOrigin: string): string {
41
70
  const initiatorOrigin = new URL(initiatorUrl).origin;
42
71
  if (initiatorOrigin === allowedOrigin) {
@@ -45,8 +74,6 @@ export class NetworkRequestFormatter {
45
74
  return '<redacted cross-origin initiator URL>';
46
75
  }
47
76
 
48
- #request: SDK.NetworkRequest.NetworkRequest;
49
-
50
77
  constructor(
51
78
  request: SDK.NetworkRequest.NetworkRequest, calculator: NetworkTimeCalculator.NetworkTransferTimeCalculator) {
52
79
  this.#request = request;
@@ -61,16 +88,27 @@ export class NetworkRequestFormatter {
61
88
  return NetworkRequestFormatter.formatHeaders('Response headers:', this.#request.responseHeaders);
62
89
  }
63
90
 
91
+ async formatResponseBody(): Promise<string> {
92
+ return await NetworkRequestFormatter.formatBody('Response body:', this.#request, MAX_BODY_SIZE);
93
+ }
94
+
64
95
  /**
65
96
  * Note: nothing here should include information from origins other than
66
97
  * the request's origin.
67
98
  */
68
- formatNetworkRequest(): string {
99
+ async formatNetworkRequest(): Promise<string> {
100
+ let responseBody = await this.formatResponseBody();
101
+
102
+ if (responseBody) {
103
+ // if we have a response then we add 2 new line to follow same structure of the context
104
+ responseBody = `\n\n${responseBody}`;
105
+ }
106
+
69
107
  return `Request: ${this.#request.url()}
70
108
 
71
109
  ${this.formatRequestHeaders()}
72
110
 
73
- ${this.formatResponseHeaders()}
111
+ ${this.formatResponseHeaders()}${responseBody}
74
112
 
75
113
  Response status: ${this.#request.statusCode} ${this.#request.statusText}
76
114