chrome-devtools-mcp 0.8.1 → 0.9.0

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 (87) hide show
  1. package/README.md +58 -3
  2. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Gzip.js +8 -6
  3. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Settings.js +1 -1
  4. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Worker.js +10 -2
  5. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/UserMetrics.js +2 -1
  6. package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/ArrayUtilities.js +1 -1
  7. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/ConnectionTransport.js +12 -0
  8. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/InspectorBackend.js +15 -27
  9. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/protocol_client.js +2 -8
  10. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMatchedStyles.js +42 -7
  11. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSRule.js +34 -6
  12. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ChildTargetManager.js +3 -0
  13. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/Connections.js +2 -2
  14. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DOMModel.js +3 -0
  15. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DebuggerModel.js +2 -1
  16. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkManager.js +336 -40
  17. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/PreloadingModel.js +56 -13
  18. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RehydratingConnection.js +32 -7
  19. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ResourceTreeModel.js +1 -1
  20. package/build/node_modules/chrome-devtools-frontend/front_end/{models/source_map_scopes → core/sdk}/ScopeTreeCache.js +9 -5
  21. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMap.js +48 -11
  22. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapManager.js +8 -2
  23. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapScopesInfo.js +131 -8
  24. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TargetManager.js +0 -21
  25. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TraceObject.js +9 -6
  26. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/sdk.js +2 -1
  27. package/build/node_modules/chrome-devtools-frontend/front_end/generated/ARIAProperties.js +1301 -174
  28. package/build/node_modules/chrome-devtools-frontend/front_end/generated/Deprecation.js +7 -0
  29. package/build/node_modules/chrome-devtools-frontend/front_end/generated/InspectorBackendCommands.js +8 -6
  30. package/build/node_modules/chrome-devtools-frontend/front_end/generated/SupportedCSSProperties.js +16 -19
  31. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.js +50 -34
  32. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AICallTree.js +2 -3
  33. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CompilerScriptMapping.js +45 -2
  34. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +14 -0
  35. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/NamesResolver.js +5 -11
  36. package/build/node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes/source_map_scopes.js +1 -2
  37. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/Trie.js +8 -0
  38. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/ModelImpl.js +6 -3
  39. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/TraceTree.js +10 -3
  40. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/MetaHandler.js +4 -1
  41. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/UserTimingsHandler.js +1 -1
  42. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/CLSCulprits.js +2 -1
  43. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Cache.js +2 -1
  44. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DOMSize.js +2 -1
  45. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DocumentLatency.js +2 -1
  46. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DuplicatedJavaScript.js +2 -1
  47. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/FontDisplay.js +2 -1
  48. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ForcedReflow.js +3 -2
  49. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/INPBreakdown.js +2 -1
  50. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ImageDelivery.js +2 -1
  51. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +2 -1
  52. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPDiscovery.js +2 -1
  53. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LegacyJavaScript.js +2 -1
  54. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ModernHTTP.js +2 -1
  55. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +2 -1
  56. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/RenderBlocking.js +2 -1
  57. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/SlowCSSSelector.js +2 -1
  58. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ThirdParties.js +2 -1
  59. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Viewport.js +2 -1
  60. package/build/src/DevToolsConnectionAdapter.js +32 -0
  61. package/build/src/McpContext.js +70 -31
  62. package/build/src/McpResponse.js +145 -44
  63. package/build/src/PageCollector.js +110 -26
  64. package/build/src/WaitForHelper.js +5 -0
  65. package/build/src/browser.js +16 -4
  66. package/build/src/cli.js +82 -6
  67. package/build/src/formatters/consoleFormatter.js +29 -62
  68. package/build/src/formatters/networkFormatter.js +5 -6
  69. package/build/src/formatters/snapshotFormatter.js +10 -5
  70. package/build/src/logger.js +1 -1
  71. package/build/src/main.js +18 -5
  72. package/build/src/polyfill.js +2 -2
  73. package/build/src/third_party/THIRD_PARTY_NOTICES +1393 -0
  74. package/build/src/third_party/index.js +76159 -0
  75. package/build/src/tools/ToolDefinition.js +2 -2
  76. package/build/src/tools/categories.js +17 -9
  77. package/build/src/tools/console.js +71 -6
  78. package/build/src/tools/emulation.js +6 -7
  79. package/build/src/tools/input.js +21 -21
  80. package/build/src/tools/network.js +18 -10
  81. package/build/src/tools/pages.js +19 -19
  82. package/build/src/tools/performance.js +8 -8
  83. package/build/src/tools/screenshot.js +8 -8
  84. package/build/src/tools/script.js +29 -15
  85. package/build/src/tools/snapshot.js +15 -20
  86. package/build/src/utils/types.js +6 -0
  87. package/package.json +16 -13
@@ -1,6 +1,7 @@
1
1
  // Copyright 2011 The Chromium Authors
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
+ var _a;
4
5
  import * as TextUtils from '../../models/text_utils/text_utils.js';
5
6
  import * as Common from '../common/common.js';
6
7
  import * as Host from '../host/host.js';
@@ -50,6 +51,10 @@ const UIStrings = {
50
51
  * @description Text in Network Manager representing the "Fast 4G" throttling preset
51
52
  */
52
53
  fast4G: 'Fast 4G',
54
+ /**
55
+ * @description Text in Network Manager representing the "Blocking" throttling preset
56
+ */
57
+ block: 'Block',
53
58
  /**
54
59
  * @description Text in Network Manager
55
60
  * @example {https://example.com} PH1
@@ -137,6 +142,8 @@ export class NetworkManager extends SDKModel {
137
142
  }
138
143
  void this.#networkAgent.invoke_enable({
139
144
  maxPostDataSize: MAX_EAGER_POST_REQUEST_BODY_LENGTH,
145
+ enableDurableMessages: Root.Runtime.hostConfig.devToolsEnableDurableMessages?.enabled,
146
+ maxTotalBufferSize: MAX_RESPONSE_BODY_TOTAL_BUFFER_LENGTH,
140
147
  reportDirectSocketTraffic: true,
141
148
  });
142
149
  void this.#networkAgent.invoke_setAttachDebugStack({ enabled: true });
@@ -364,6 +371,11 @@ export var Events;
364
371
  * @see https://docs.google.com/document/d/10lfVdS1iDWCRKQXPfbxEn4Or99D64mvNlugP1AQuFlE/edit for historical context.
365
372
  * @see https://crbug.com/342406608#comment10 for context around the addition of 4G presets in June 2024.
366
373
  */
374
+ export const BlockingConditions = {
375
+ key: "BLOCKING" /* PredefinedThrottlingConditionKey.BLOCKING */,
376
+ block: true,
377
+ title: i18nLazyString(UIStrings.block),
378
+ };
367
379
  export const NoThrottlingConditions = {
368
380
  key: "NO_THROTTLING" /* PredefinedThrottlingConditionKey.NO_THROTTLING */,
369
381
  title: i18nLazyString(UIStrings.noThrottling),
@@ -422,6 +434,7 @@ export const Fast4GConditions = {
422
434
  targetLatency: fast4GTargetLatency,
423
435
  };
424
436
  const MAX_EAGER_POST_REQUEST_BODY_LENGTH = 64 * 1024; // bytes
437
+ const MAX_RESPONSE_BODY_TOTAL_BUFFER_LENGTH = 250 * 1024 * 1024; // bytes
425
438
  export class FetchDispatcher {
426
439
  #fetchAgent;
427
440
  #manager;
@@ -1267,6 +1280,289 @@ export class NetworkDispatcher {
1267
1280
  return `${host}:${port}`;
1268
1281
  }
1269
1282
  }
1283
+ export class RequestURLPattern {
1284
+ constructorString;
1285
+ pattern;
1286
+ constructor(constructorString, pattern) {
1287
+ this.constructorString = constructorString;
1288
+ this.pattern = pattern;
1289
+ if (pattern.hasRegExpGroups) {
1290
+ throw new Error('RegExp groups are not allowed');
1291
+ }
1292
+ }
1293
+ static isValidPattern(pattern) {
1294
+ try {
1295
+ const urlPattern = new URLPattern(pattern);
1296
+ return urlPattern.hasRegExpGroups ? "has-regexp-groups" /* RequestURLPatternValidity.HAS_REGEXP_GROUPS */ : "valid" /* RequestURLPatternValidity.VALID */;
1297
+ }
1298
+ catch {
1299
+ return "failed-to-parse" /* RequestURLPatternValidity.FAILED_TO_PARSE */;
1300
+ }
1301
+ }
1302
+ static create(constructorString) {
1303
+ try {
1304
+ const urlPattern = new URLPattern(constructorString);
1305
+ return urlPattern.hasRegExpGroups ? null : new RequestURLPattern(constructorString, urlPattern);
1306
+ }
1307
+ catch {
1308
+ return null;
1309
+ }
1310
+ }
1311
+ static upgradeFromWildcard(pattern) {
1312
+ const tryCreate = (constructorString) => {
1313
+ const result = this.create(constructorString);
1314
+ if (result?.pattern.protocol === 'localhost' && result?.pattern.hostname === '') {
1315
+ // localhost:1234 parses as a valid pattern, do the right thing here instead
1316
+ return tryCreate(`*://${constructorString}`);
1317
+ }
1318
+ return result;
1319
+ };
1320
+ return tryCreate(pattern) // try as is
1321
+ ??
1322
+ // Try to upgrade patterns created from the network panel, which either blocks the full url (sans
1323
+ // protocol) or just the domain name. In both cases the wildcard patterns had implicit wildcards at the end.
1324
+ // We explicitly add that here, which will match both domain names without path (implicitly setting pathname
1325
+ // to '*') and urls with path (appending * to the pathname).
1326
+ tryCreate(`*://${pattern}*`);
1327
+ }
1328
+ }
1329
+ export class RequestCondition extends Common.ObjectWrapper.ObjectWrapper {
1330
+ #pattern;
1331
+ #enabled;
1332
+ #conditions;
1333
+ static createFromSetting(setting) {
1334
+ if ('urlPattern' in setting) {
1335
+ const pattern = RequestURLPattern.create(setting.urlPattern) ?? {
1336
+ wildcardURL: setting.urlPattern,
1337
+ upgradedPattern: RequestURLPattern.upgradeFromWildcard(setting.urlPattern) ?? undefined,
1338
+ };
1339
+ const conditions = getPredefinedOrBlockingCondition(setting.conditions) ??
1340
+ customUserNetworkConditionsSetting().get().find(condition => condition.key === setting.conditions) ??
1341
+ NoThrottlingConditions;
1342
+ return new this(pattern, setting.enabled, conditions);
1343
+ }
1344
+ const pattern = {
1345
+ wildcardURL: setting.url,
1346
+ upgradedPattern: RequestURLPattern.upgradeFromWildcard(setting.url) ?? undefined
1347
+ };
1348
+ return new this(pattern, setting.enabled, BlockingConditions);
1349
+ }
1350
+ static create(pattern, conditions) {
1351
+ return new this(pattern, /* enabled=*/ true, conditions);
1352
+ }
1353
+ constructor(pattern, enabled, conditions) {
1354
+ super();
1355
+ this.#pattern = pattern;
1356
+ this.#enabled = enabled;
1357
+ this.#conditions = conditions;
1358
+ }
1359
+ get constructorString() {
1360
+ return this.#pattern instanceof RequestURLPattern ? this.#pattern.constructorString :
1361
+ this.#pattern.upgradedPattern?.constructorString;
1362
+ }
1363
+ get wildcardURL() {
1364
+ return 'wildcardURL' in this.#pattern ? this.#pattern.wildcardURL : undefined;
1365
+ }
1366
+ get constructorStringOrWildcardURL() {
1367
+ return this.#pattern instanceof RequestURLPattern ?
1368
+ this.#pattern.constructorString :
1369
+ (this.#pattern.upgradedPattern?.constructorString ?? this.#pattern.wildcardURL);
1370
+ }
1371
+ set pattern(pattern) {
1372
+ if (typeof pattern === 'string') {
1373
+ // TODO(pfaffe) Remove once the feature flag is no longer required
1374
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
1375
+ throw new Error('Should not use wildcard urls');
1376
+ }
1377
+ this.#pattern = {
1378
+ wildcardURL: pattern,
1379
+ upgradedPattern: RequestURLPattern.upgradeFromWildcard(pattern) ?? undefined
1380
+ };
1381
+ }
1382
+ else {
1383
+ this.#pattern = pattern;
1384
+ }
1385
+ this.dispatchEventToListeners("request-condition-changed" /* RequestCondition.Events.REQUEST_CONDITION_CHANGED */);
1386
+ }
1387
+ get enabled() {
1388
+ return this.#enabled;
1389
+ }
1390
+ set enabled(enabled) {
1391
+ this.#enabled = enabled;
1392
+ this.dispatchEventToListeners("request-condition-changed" /* RequestCondition.Events.REQUEST_CONDITION_CHANGED */);
1393
+ }
1394
+ get conditions() {
1395
+ return this.#conditions;
1396
+ }
1397
+ set conditions(conditions) {
1398
+ this.#conditions = conditions;
1399
+ this.dispatchEventToListeners("request-condition-changed" /* RequestCondition.Events.REQUEST_CONDITION_CHANGED */);
1400
+ }
1401
+ toSetting() {
1402
+ const enabled = this.enabled;
1403
+ if (this.#pattern instanceof RequestURLPattern) {
1404
+ return { enabled, urlPattern: this.#pattern.constructorString, conditions: this.#conditions.key };
1405
+ }
1406
+ if (this.#conditions !== BlockingConditions && this.#pattern.upgradedPattern) {
1407
+ return { enabled, urlPattern: this.#pattern.upgradedPattern.constructorString, conditions: this.#conditions.key };
1408
+ }
1409
+ return { enabled, url: this.#pattern.wildcardURL };
1410
+ }
1411
+ get originalOrUpgradedURLPattern() {
1412
+ return this.#pattern instanceof RequestURLPattern ? this.#pattern.pattern : this.#pattern.upgradedPattern?.pattern;
1413
+ }
1414
+ }
1415
+ export class RequestConditions extends Common.ObjectWrapper.ObjectWrapper {
1416
+ #setting = Common.Settings.Settings.instance().createSetting('network-blocked-patterns', []);
1417
+ #conditionsEnabledSetting = Common.Settings.Settings.instance().moduleSetting('request-blocking-enabled');
1418
+ #conditions = [];
1419
+ constructor() {
1420
+ super();
1421
+ for (const condition of this.#setting.get()) {
1422
+ try {
1423
+ this.#conditions.push(RequestCondition.createFromSetting(condition));
1424
+ }
1425
+ catch (e) {
1426
+ console.error('Error loading throttling settings: ', e);
1427
+ }
1428
+ }
1429
+ for (const condition of this.#conditions) {
1430
+ condition.addEventListener("request-condition-changed" /* RequestCondition.Events.REQUEST_CONDITION_CHANGED */, this.#conditionsChanged, this);
1431
+ }
1432
+ this.#conditionsEnabledSetting.addChangeListener(() => this.dispatchEventToListeners("request-conditions-changed" /* RequestConditions.Events.REQUEST_CONDITIONS_CHANGED */));
1433
+ }
1434
+ get count() {
1435
+ return this.#conditions.length;
1436
+ }
1437
+ get conditionsEnabled() {
1438
+ return this.#conditionsEnabledSetting.get();
1439
+ }
1440
+ set conditionsEnabled(enabled) {
1441
+ if (this.#conditionsEnabledSetting.get() === enabled) {
1442
+ return;
1443
+ }
1444
+ this.#conditionsEnabledSetting.set(enabled);
1445
+ }
1446
+ findCondition(pattern) {
1447
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
1448
+ return this.#conditions.find(condition => condition.constructorString === pattern);
1449
+ }
1450
+ return this.#conditions.find(condition => condition.wildcardURL === pattern);
1451
+ }
1452
+ has(url) {
1453
+ return Boolean(this.findCondition(url));
1454
+ }
1455
+ add(...conditions) {
1456
+ this.#conditions.push(...conditions);
1457
+ for (const condition of conditions) {
1458
+ condition.addEventListener("request-condition-changed" /* RequestCondition.Events.REQUEST_CONDITION_CHANGED */, this.#conditionsChanged, this);
1459
+ }
1460
+ this.#conditionsChanged();
1461
+ }
1462
+ decreasePriority(condition) {
1463
+ const index = this.#conditions.indexOf(condition);
1464
+ if (index < 0 || index >= this.#conditions.length - 1) {
1465
+ return;
1466
+ }
1467
+ Platform.ArrayUtilities.swap(this.#conditions, index, index + 1);
1468
+ this.dispatchEventToListeners("request-conditions-changed" /* RequestConditions.Events.REQUEST_CONDITIONS_CHANGED */);
1469
+ }
1470
+ increasePriority(condition) {
1471
+ const index = this.#conditions.indexOf(condition);
1472
+ if (index <= 0) {
1473
+ return;
1474
+ }
1475
+ Platform.ArrayUtilities.swap(this.#conditions, index - 1, index);
1476
+ this.dispatchEventToListeners("request-conditions-changed" /* RequestConditions.Events.REQUEST_CONDITIONS_CHANGED */);
1477
+ }
1478
+ delete(condition) {
1479
+ const index = this.#conditions.indexOf(condition);
1480
+ if (index < 0) {
1481
+ return;
1482
+ }
1483
+ condition.removeEventListener("request-condition-changed" /* RequestCondition.Events.REQUEST_CONDITION_CHANGED */, this.#conditionsChanged, this);
1484
+ this.#conditions.splice(index, 1);
1485
+ this.#conditionsChanged();
1486
+ }
1487
+ clear() {
1488
+ this.#conditions.splice(0);
1489
+ this.#conditionsChanged();
1490
+ for (const condition of this.#conditions) {
1491
+ condition.removeEventListener("request-condition-changed" /* RequestCondition.Events.REQUEST_CONDITION_CHANGED */, this.#conditionsChanged, this);
1492
+ }
1493
+ }
1494
+ #conditionsChanged() {
1495
+ this.#setting.set(this.#conditions.map(condition => condition.toSetting()));
1496
+ this.dispatchEventToListeners("request-conditions-changed" /* RequestConditions.Events.REQUEST_CONDITIONS_CHANGED */);
1497
+ }
1498
+ get conditions() {
1499
+ return this.#conditions.values();
1500
+ }
1501
+ applyConditions(offline, globalConditions, ...agents) {
1502
+ function isNonBlockingCondition(condition) {
1503
+ return !('block' in condition);
1504
+ }
1505
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
1506
+ const urlPatterns = [];
1507
+ const matchedNetworkConditions = [];
1508
+ if (this.conditionsEnabled) {
1509
+ for (const condition of this.#conditions) {
1510
+ const urlPattern = condition.constructorString;
1511
+ const conditions = condition.conditions;
1512
+ if (!condition.enabled || !urlPattern || conditions === NoThrottlingConditions) {
1513
+ continue;
1514
+ }
1515
+ const block = !isNonBlockingCondition(conditions);
1516
+ urlPatterns.push({ urlPattern, block });
1517
+ if (!block) {
1518
+ matchedNetworkConditions.push({
1519
+ urlPattern,
1520
+ latency: conditions.latency,
1521
+ downloadThroughput: conditions.download < 0 ? 0 : conditions.download,
1522
+ uploadThroughput: conditions.upload < 0 ? 0 : conditions.upload,
1523
+ packetLoss: (conditions.packetLoss ?? 0) < 0 ? 0 : conditions.packetLoss,
1524
+ packetQueueLength: conditions.packetQueueLength,
1525
+ packetReordering: conditions.packetReordering,
1526
+ connectionType: NetworkManager.connectionType(conditions),
1527
+ });
1528
+ }
1529
+ }
1530
+ if (globalConditions) {
1531
+ matchedNetworkConditions.push({
1532
+ urlPattern: '',
1533
+ latency: globalConditions.latency,
1534
+ downloadThroughput: globalConditions.download < 0 ? 0 : globalConditions.download,
1535
+ uploadThroughput: globalConditions.upload < 0 ? 0 : globalConditions.upload,
1536
+ packetLoss: (globalConditions.packetLoss ?? 0) < 0 ? 0 : globalConditions.packetLoss,
1537
+ packetQueueLength: globalConditions.packetQueueLength,
1538
+ packetReordering: globalConditions.packetReordering,
1539
+ connectionType: NetworkManager.connectionType(globalConditions),
1540
+ });
1541
+ }
1542
+ }
1543
+ for (const agent of agents) {
1544
+ void agent.invoke_setBlockedURLs({ urlPatterns });
1545
+ void agent.invoke_emulateNetworkConditionsByRule({ offline, matchedNetworkConditions });
1546
+ void agent.invoke_overrideNetworkState({
1547
+ offline,
1548
+ latency: globalConditions?.latency ?? 0,
1549
+ downloadThroughput: !globalConditions || globalConditions.download < 0 ? 0 : globalConditions.download,
1550
+ uploadThroughput: !globalConditions || globalConditions.upload < 0 ? 0 : globalConditions.upload,
1551
+ });
1552
+ }
1553
+ return urlPatterns.length > 0;
1554
+ }
1555
+ const urls = this.conditionsEnabled ?
1556
+ this.#conditions.filter(condition => condition.enabled && condition.wildcardURL)
1557
+ .map(condition => condition.wildcardURL) :
1558
+ [];
1559
+ for (const agent of agents) {
1560
+ void agent.invoke_setBlockedURLs({ urls });
1561
+ }
1562
+ return urls.length > 0;
1563
+ }
1564
+ }
1565
+ _a = RequestConditions;
1270
1566
  let multiTargetNetworkManagerInstance;
1271
1567
  export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrapper {
1272
1568
  #userAgentOverride = '';
@@ -1277,12 +1573,11 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1277
1573
  inflightMainResourceRequests = new Map();
1278
1574
  #networkConditions = NoThrottlingConditions;
1279
1575
  #updatingInterceptionPatternsPromise = null;
1280
- #blockingEnabledSetting = Common.Settings.Settings.instance().moduleSetting('request-blocking-enabled');
1281
- #blockedPatternsSetting = Common.Settings.Settings.instance().createSetting('network-blocked-patterns', []);
1282
- #effectiveBlockedURLs = [];
1576
+ #requestConditions = new RequestConditions();
1283
1577
  #urlsForRequestInterceptor = new Platform.MapUtilities.Multimap();
1284
1578
  #extraHeaders;
1285
1579
  #customUserAgent;
1580
+ #isBlocking = false;
1286
1581
  constructor() {
1287
1582
  super();
1288
1583
  // TODO(allada) Remove these and merge it with request interception.
@@ -1290,8 +1585,7 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1290
1585
  this.updateBlockedPatterns();
1291
1586
  this.dispatchEventToListeners("BlockedPatternsChanged" /* MultitargetNetworkManager.Events.BLOCKED_PATTERNS_CHANGED */);
1292
1587
  };
1293
- this.#blockingEnabledSetting.addChangeListener(blockedPatternChanged);
1294
- this.#blockedPatternsSetting.addChangeListener(blockedPatternChanged);
1588
+ this.#requestConditions.addEventListener("request-conditions-changed" /* RequestConditions.Events.REQUEST_CONDITIONS_CHANGED */, blockedPatternChanged);
1295
1589
  this.updateBlockedPatterns();
1296
1590
  TargetManager.instance().observeModels(NetworkManager, this);
1297
1591
  }
@@ -1347,9 +1641,7 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1347
1641
  if (this.currentUserAgent()) {
1348
1642
  void networkAgent.invoke_setUserAgentOverride({ userAgent: this.currentUserAgent(), userAgentMetadata: this.#userAgentMetadataOverride || undefined });
1349
1643
  }
1350
- if (this.#effectiveBlockedURLs.length) {
1351
- void networkAgent.invoke_setBlockedURLs({ urls: this.#effectiveBlockedURLs });
1352
- }
1644
+ this.#requestConditions.applyConditions(this.isOffline(), this.isThrottling() ? this.#networkConditions : null, networkAgent);
1353
1645
  if (this.isIntercepting()) {
1354
1646
  void fetchAgent.invoke_enable({ patterns: this.#urlsForRequestInterceptor.valuesArray() });
1355
1647
  }
@@ -1361,7 +1653,7 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1361
1653
  }
1362
1654
  this.#networkAgents.add(networkAgent);
1363
1655
  this.#fetchAgents.add(fetchAgent);
1364
- if (this.isThrottling()) {
1656
+ if (this.isThrottling() && !Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
1365
1657
  this.updateNetworkConditions(networkAgent);
1366
1658
  }
1367
1659
  }
@@ -1385,8 +1677,13 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1385
1677
  }
1386
1678
  setNetworkConditions(conditions) {
1387
1679
  this.#networkConditions = conditions;
1388
- for (const agent of this.#networkAgents) {
1389
- this.updateNetworkConditions(agent);
1680
+ if (Root.Runtime.hostConfig.devToolsIndividualRequestThrottling?.enabled) {
1681
+ this.#requestConditions.applyConditions(this.isOffline(), this.isThrottling() ? this.#networkConditions : null, ...this.#networkAgents);
1682
+ }
1683
+ else {
1684
+ for (const agent of this.#networkAgents) {
1685
+ this.updateNetworkConditions(agent);
1686
+ }
1390
1687
  }
1391
1688
  this.dispatchEventToListeners("ConditionsChanged" /* MultitargetNetworkManager.Events.CONDITIONS_CHANGED */);
1392
1689
  }
@@ -1474,41 +1771,29 @@ export class MultitargetNetworkManager extends Common.ObjectWrapper.ObjectWrappe
1474
1771
  }
1475
1772
  }
1476
1773
  }
1477
- // TODO(allada) Move all request blocking into interception and let view manage blocking.
1478
- blockedPatterns() {
1479
- return this.#blockedPatternsSetting.get().slice();
1480
- }
1481
- blockingEnabled() {
1482
- return this.#blockingEnabledSetting.get();
1774
+ get requestConditions() {
1775
+ return this.#requestConditions;
1483
1776
  }
1484
1777
  isBlocking() {
1485
- return Boolean(this.#effectiveBlockedURLs.length);
1486
- }
1487
- setBlockedPatterns(patterns) {
1488
- this.#blockedPatternsSetting.set(patterns);
1778
+ return this.#isBlocking && this.requestConditions.conditionsEnabled;
1489
1779
  }
1780
+ /**
1781
+ * @deprecated Kept for layout tests
1782
+ * TODO(pfaffe) remove
1783
+ */
1490
1784
  setBlockingEnabled(enabled) {
1491
- if (this.#blockingEnabledSetting.get() === enabled) {
1492
- return;
1493
- }
1494
- this.#blockingEnabledSetting.set(enabled);
1785
+ this.requestConditions.conditionsEnabled = enabled;
1786
+ }
1787
+ /**
1788
+ * @deprecated Kept for layout tests
1789
+ * TODO(pfaffe) remove
1790
+ */
1791
+ setBlockedPatterns(patterns) {
1792
+ this.requestConditions.clear();
1793
+ this.requestConditions.add(...patterns.map(pattern => RequestCondition.createFromSetting(pattern)));
1495
1794
  }
1496
1795
  updateBlockedPatterns() {
1497
- const urls = [];
1498
- if (this.#blockingEnabledSetting.get()) {
1499
- for (const pattern of this.#blockedPatternsSetting.get()) {
1500
- if (pattern.enabled) {
1501
- urls.push(pattern.url);
1502
- }
1503
- }
1504
- }
1505
- if (!urls.length && !this.#effectiveBlockedURLs.length) {
1506
- return;
1507
- }
1508
- this.#effectiveBlockedURLs = urls;
1509
- for (const agent of this.#networkAgents) {
1510
- void agent.invoke_setBlockedURLs({ urls: this.#effectiveBlockedURLs });
1511
- }
1796
+ this.#isBlocking = this.#requestConditions.applyConditions(this.isOffline(), this.isThrottling() ? this.#networkConditions : null, ...this.#networkAgents);
1512
1797
  }
1513
1798
  isIntercepting() {
1514
1799
  return Boolean(this.#urlsForRequestInterceptor.size);
@@ -1814,6 +2099,14 @@ class ExtraInfoBuilder {
1814
2099
  }
1815
2100
  SDKModel.register(NetworkManager, { capabilities: 16 /* Capability.NETWORK */, autostart: true });
1816
2101
  export function networkConditionsEqual(first, second) {
2102
+ if ('block' in first || 'block' in second) {
2103
+ if ('block' in first && 'block' in second) {
2104
+ const firstTitle = (typeof first.title === 'function' ? first.title() : first.title);
2105
+ const secondTitle = (typeof second.title === 'function' ? second.title() : second.title);
2106
+ return firstTitle === secondTitle && first.block === second.block;
2107
+ }
2108
+ return false;
2109
+ }
1817
2110
  // Caution: titles might be different function instances, which produce
1818
2111
  // the same value.
1819
2112
  // We prefer to use the i18nTitleKey to prevent against locale changes or
@@ -1844,6 +2137,9 @@ export function getPredefinedCondition(key) {
1844
2137
  }
1845
2138
  return THROTTLING_CONDITIONS_LOOKUP.get(key) ?? null;
1846
2139
  }
2140
+ export function getPredefinedOrBlockingCondition(key) {
2141
+ return key === "BLOCKING" /* PredefinedThrottlingConditionKey.BLOCKING */ ? BlockingConditions : getPredefinedCondition(key);
2142
+ }
1847
2143
  /**
1848
2144
  * For the given Round Trip Time (in MilliSeconds), return the best throttling conditions.
1849
2145
  */
@@ -228,15 +228,33 @@ export class PreloadingModel extends SDKModel {
228
228
  onPrerenderStatusUpdated(event) {
229
229
  const loaderId = event.key.loaderId;
230
230
  this.ensureDocumentPreloadingData(loaderId);
231
- const attempt = {
232
- action: "Prerender" /* Protocol.Preload.SpeculationAction.Prerender */,
233
- key: event.key,
234
- pipelineId: event.pipelineId,
235
- status: convertPreloadingStatus(event.status),
236
- prerenderStatus: event.prerenderStatus || null,
237
- disallowedMojoInterface: event.disallowedMojoInterface || null,
238
- mismatchedHeaders: event.mismatchedHeaders || null,
239
- };
231
+ let attempt;
232
+ switch (event.key.action) {
233
+ case "Prerender" /* Protocol.Preload.SpeculationAction.Prerender */:
234
+ attempt = {
235
+ action: event.key.action,
236
+ key: event.key,
237
+ pipelineId: event.pipelineId,
238
+ status: convertPreloadingStatus(event.status),
239
+ prerenderStatus: event.prerenderStatus || null,
240
+ disallowedMojoInterface: event.disallowedMojoInterface || null,
241
+ mismatchedHeaders: event.mismatchedHeaders || null,
242
+ };
243
+ break;
244
+ case "PrerenderUntilScript" /* Protocol.Preload.SpeculationAction.PrerenderUntilScript */:
245
+ attempt = {
246
+ action: event.key.action,
247
+ key: event.key,
248
+ pipelineId: event.pipelineId,
249
+ status: convertPreloadingStatus(event.status),
250
+ prerenderStatus: event.prerenderStatus || null,
251
+ disallowedMojoInterface: event.disallowedMojoInterface || null,
252
+ mismatchedHeaders: event.mismatchedHeaders || null,
253
+ };
254
+ break;
255
+ default:
256
+ throw new Error(`unreachable: event.key.action: ${event.key.action}`);
257
+ }
240
258
  this.documents.get(loaderId)?.preloadingAttempts.upsert(attempt);
241
259
  this.dispatchEventToListeners("ModelUpdated" /* Events.MODEL_UPDATED */);
242
260
  }
@@ -335,6 +353,9 @@ function makePreloadingAttemptId(key) {
335
353
  case "Prerender" /* Protocol.Preload.SpeculationAction.Prerender */:
336
354
  action = 'Prerender';
337
355
  break;
356
+ case "PrerenderUntilScript" /* Protocol.Preload.SpeculationAction.PrerenderUntilScript */:
357
+ action = 'PrerenderUntilScript';
358
+ break;
338
359
  }
339
360
  let targetHint;
340
361
  switch (key.targetHint) {
@@ -366,7 +387,7 @@ export class PreloadPipeline {
366
387
  return new PreloadPipeline(inner);
367
388
  }
368
389
  getOriginallyTriggered() {
369
- const attempt = this.getPrerender() || this.getPrefetch();
390
+ const attempt = this.getPrerender() || this.getPrerenderUntilScript() || this.getPrefetch();
370
391
  assertNotNullOrUndefined(attempt);
371
392
  return attempt;
372
393
  }
@@ -376,7 +397,10 @@ export class PreloadPipeline {
376
397
  getPrerender() {
377
398
  return this.inner.get("Prerender" /* Protocol.Preload.SpeculationAction.Prerender */) || null;
378
399
  }
379
- // Returns attempts in the order: prefetch < prerender.
400
+ getPrerenderUntilScript() {
401
+ return this.inner.get("PrerenderUntilScript" /* Protocol.Preload.SpeculationAction.PrerenderUntilScript */) || null;
402
+ }
403
+ // Returns attempts in the order: prefetch < prerender_until_script < prerender.
380
404
  // Currently unused.
381
405
  getAttempts() {
382
406
  const ret = [];
@@ -388,6 +412,10 @@ export class PreloadPipeline {
388
412
  if (prerender !== null) {
389
413
  ret.push(prerender);
390
414
  }
415
+ const prerenderUntilScript = this.getPrerenderUntilScript();
416
+ if (prerenderUntilScript !== null) {
417
+ ret.push(prerenderUntilScript);
418
+ }
391
419
  if (ret.length === 0) {
392
420
  throw new Error('unreachable');
393
421
  }
@@ -414,7 +442,9 @@ class PreloadingAttemptRegistry {
414
442
  //
415
443
  // In some cases, browsers automatically triggers preloads. For example, Chrome triggers prefetch
416
444
  // ahead of prerender to prevent multiple fetches in case that the prerender failed due to, e.g.
417
- // use of forbidden mojo APIs. Such prefetch and prerender sit in the same preload pipeline.
445
+ // use of forbidden mojo APIs. Also, a prerender-until-script attempt triggers prefetch as well,
446
+ // and can upgrade to prerender. Such prefetch, prerender-until-script, and prerender sit in the
447
+ // same preload pipeline.
418
448
  //
419
449
  // We regard them as not representative and only show the representative ones to represent
420
450
  // pipelines.
@@ -423,8 +453,10 @@ class PreloadingAttemptRegistry {
423
453
  switch (action) {
424
454
  case "Prefetch" /* Protocol.Preload.SpeculationAction.Prefetch */:
425
455
  return 0;
426
- case "Prerender" /* Protocol.Preload.SpeculationAction.Prerender */:
456
+ case "PrerenderUntilScript" /* Protocol.Preload.SpeculationAction.PrerenderUntilScript */:
427
457
  return 1;
458
+ case "Prerender" /* Protocol.Preload.SpeculationAction.Prerender */:
459
+ return 2;
428
460
  }
429
461
  }
430
462
  // Attempt with status `NOT_TRIGGERED` is a representative of a pipeline.
@@ -527,6 +559,17 @@ class PreloadingAttemptRegistry {
527
559
  mismatchedHeaders: null,
528
560
  };
529
561
  break;
562
+ case "PrerenderUntilScript" /* Protocol.Preload.SpeculationAction.PrerenderUntilScript */:
563
+ attempt = {
564
+ action: "PrerenderUntilScript" /* Protocol.Preload.SpeculationAction.PrerenderUntilScript */,
565
+ key,
566
+ pipelineId: null,
567
+ status: "NotTriggered" /* PreloadingStatus.NOT_TRIGGERED */,
568
+ prerenderStatus: null,
569
+ disallowedMojoInterface: null,
570
+ mismatchedHeaders: null,
571
+ };
572
+ break;
530
573
  }
531
574
  this.map.set(id, attempt);
532
575
  }
@@ -3,6 +3,7 @@
3
3
  // found in the LICENSE file.
4
4
  import * as Common from '../common/common.js';
5
5
  import * as i18n from '../i18n/i18n.js';
6
+ import * as Root from '../root/root.js';
6
7
  import * as EnhancedTraces from './EnhancedTracesParser.js';
7
8
  import { TraceObject } from './TraceObject.js';
8
9
  const UIStrings = {
@@ -28,21 +29,45 @@ export class RehydratingConnection {
28
29
  trace = null;
29
30
  sessions = new Map();
30
31
  #onConnectionLost;
31
- #rehydratingWindow;
32
+ #rehydratingWindow = window;
32
33
  #onReceiveHostWindowPayloadBound = this.onReceiveHostWindowPayload.bind(this);
33
34
  constructor(onConnectionLost) {
34
- // If we're invoking this class, we're in the rehydrating pop-up window. Rename window for clarity.
35
35
  this.#onConnectionLost = onConnectionLost;
36
- this.#rehydratingWindow = window;
37
- this.#setupMessagePassing();
36
+ if (!this.#maybeHandleLoadingFromUrl()) {
37
+ this.#setupMessagePassing();
38
+ }
39
+ }
40
+ /** Returns true if found a trace URL. */
41
+ #maybeHandleLoadingFromUrl() {
42
+ let traceUrl = Root.Runtime.Runtime.queryParam('traceURL');
43
+ if (!traceUrl) {
44
+ // For compatibility, handle the older loadTimelineFromURL.
45
+ const timelineUrl = Root.Runtime.Runtime.queryParam('loadTimelineFromURL');
46
+ if (timelineUrl) {
47
+ // It was double-URI encoded for some reason.
48
+ traceUrl = decodeURIComponent(timelineUrl);
49
+ }
50
+ }
51
+ if (traceUrl) {
52
+ void fetch(traceUrl).then(r => r.arrayBuffer()).then(b => Common.Gzip.arrayBufferToString(b)).then(traceJson => {
53
+ const trace = new TraceObject(JSON.parse(traceJson));
54
+ void this.startHydration(trace);
55
+ });
56
+ return true;
57
+ }
58
+ return false;
38
59
  }
39
60
  #setupMessagePassing() {
40
61
  this.#rehydratingWindow.addEventListener('message', this.#onReceiveHostWindowPayloadBound);
41
- if (!this.#rehydratingWindow.opener) {
62
+ if (this.#rehydratingWindow.opener) {
63
+ this.#rehydratingWindow.opener.postMessage({ type: 'REHYDRATING_WINDOW_READY' });
64
+ }
65
+ else if (this.#rehydratingWindow !== window.top) {
66
+ this.#rehydratingWindow.parent.postMessage({ type: 'REHYDRATING_IFRAME_READY' });
67
+ }
68
+ else {
42
69
  this.#onConnectionLost(i18nString(UIStrings.noHostWindow));
43
- return;
44
70
  }
45
- this.#rehydratingWindow.opener.postMessage({ type: 'REHYDRATING_WINDOW_READY' });
46
71
  }
47
72
  /**
48
73
  * This is a callback for rehydrated session to receive payload from host window. Payload includes but not limited to
@@ -87,7 +87,7 @@ export class ResourceTreeModel extends SDKModel {
87
87
  return null;
88
88
  }
89
89
  // TODO(crbug.com/445966299): Refactor to use `storageAgent().invoke_getStorageKey()` instead.
90
- const response = await this.storageAgent.invoke_getStorageKeyForFrame({ frameId });
90
+ const response = await this.storageAgent.invoke_getStorageKey({ frameId });
91
91
  if (response.getError() === 'Frame tree node for given frame not found') {
92
92
  return null;
93
93
  }