chrome-ai-bridge 1.0.3 → 1.0.5

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 (74) hide show
  1. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Base64.js +20 -2
  2. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Gzip.js +11 -0
  3. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Object.js +6 -1
  4. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ParsedURL.js +3 -0
  5. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/ResourceType.js +6 -0
  6. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Settings.js +18 -8
  7. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/InspectorFrontendHostStub.js +3 -3
  8. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/ResourceLoader.js +1 -1
  9. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/UserMetrics.js +17 -1
  10. package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/ArrayUtilities.js +10 -0
  11. package/build/node_modules/chrome-devtools-frontend/front_end/core/platform/StringUtilities.js +63 -12
  12. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/CDPConnection.js +1 -0
  13. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/InspectorBackend.js +4 -1
  14. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMatchedStyles.js +44 -9
  15. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMetadata.js +6 -6
  16. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSModel.js +1 -1
  17. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DOMModel.js +169 -12
  18. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DebuggerModel.js +2 -1
  19. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/IsolateManager.js +6 -0
  20. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkManager.js +18 -4
  21. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkRequest.js +7 -21
  22. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/OverlayModel.js +17 -5
  23. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RehydratingConnection.js +5 -1
  24. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ResourceTreeModel.js +8 -5
  25. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMap.js +14 -2
  26. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapManager.js +1 -1
  27. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMapScopesInfo.js +11 -4
  28. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/Target.js +3 -1
  29. package/build/node_modules/chrome-devtools-frontend/front_end/generated/ARIAProperties.js +1 -1
  30. package/build/node_modules/chrome-devtools-frontend/front_end/generated/Deprecation.js +1 -16
  31. package/build/node_modules/chrome-devtools-frontend/front_end/generated/InspectorBackendCommands.js +35 -14
  32. package/build/node_modules/chrome-devtools-frontend/front_end/generated/SupportedCSSProperties.js +197 -101
  33. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.js +2 -1
  34. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.js +10 -16
  35. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.js +97 -26
  36. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AICallTree.js +35 -0
  37. package/build/node_modules/chrome-devtools-frontend/front_end/models/annotations/AnnotationRepository.js +163 -0
  38. package/build/node_modules/chrome-devtools-frontend/front_end/models/annotations/AnnotationType.js +10 -0
  39. package/build/node_modules/chrome-devtools-frontend/front_end/models/annotations/annotations.js +5 -0
  40. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/CompilerScriptMapping.js +5 -3
  41. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/DebuggerWorkspaceBinding.js +7 -3
  42. package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/DeviceModeModel.js +1 -1
  43. package/build/node_modules/chrome-devtools-frontend/front_end/models/emulation/EmulatedDevices.js +14 -0
  44. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +8 -5
  45. package/build/node_modules/chrome-devtools-frontend/front_end/models/greendev/Prototypes.js +33 -0
  46. package/build/node_modules/chrome-devtools-frontend/front_end/models/greendev/greendev.js +4 -0
  47. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceImpl.js +70 -1
  48. package/build/node_modules/chrome-devtools-frontend/front_end/models/stack_trace/StackTraceModel.js +82 -30
  49. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/EventsSerializer.js +7 -2
  50. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/LanternComputationData.js +2 -2
  51. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Processor.js +18 -19
  52. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Styles.js +12 -4
  53. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/Initiators.js +46 -0
  54. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/TraceTree.js +4 -3
  55. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/extras/extras.js +1 -0
  56. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LargestImagePaintHandler.js +2 -2
  57. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LayoutShiftsHandler.js +1 -1
  58. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/MetaHandler.js +6 -0
  59. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/NetworkRequestsHandler.js +10 -1
  60. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/PageLoadMetricsHandler.js +44 -27
  61. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/helpers/Timing.js +9 -2
  62. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/Common.js +1 -6
  63. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +2 -2
  64. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPDiscovery.js +2 -4
  65. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +3 -2
  66. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/RenderBlocking.js +1 -1
  67. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/types/TraceEvents.js +30 -11
  68. package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +28 -13
  69. package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +1 -1
  70. package/build/node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +4 -0
  71. package/build/src/tools/chatgpt-web.js +68 -49
  72. package/build/src/tools/gemini-web.js +66 -22
  73. package/build/src/tools/pages.js +0 -1
  74. package/package.json +1 -1
@@ -29,13 +29,31 @@ export function decode(input) {
29
29
  }
30
30
  return bytes;
31
31
  }
32
+ /**
33
+ * Note: if input can be very large (larger than the max string size), callers should
34
+ * expect this to throw an error.
35
+ */
32
36
  export function encode(input) {
33
37
  return new Promise((resolve, reject) => {
34
38
  const reader = new FileReader();
35
- reader.onerror = () => reject(new Error('failed to convert to base64'));
39
+ reader.onerror = () => reject(new Error('failed to convert to base64: internal error'));
36
40
  reader.onload = () => {
41
+ // The input was too large to encode as a string. The caller should anticipate
42
+ // this and use a workaround. See TimelinePanel.ts innerSaveToFile for an example.
43
+ // For more information, see crbug.com/436482118.
44
+ if (reader.result === '') {
45
+ reject(new Error('failed to convert to base64: input too large to encode as base64 string'));
46
+ return;
47
+ }
48
+ // This string can be very large, so take care to not double memory. `split`
49
+ // was used here before, which always results in new strings in V8. By using
50
+ // slice instead, we leverage the sliced string optimization in V8 and avoid
51
+ // doubling the memory requirement (even if temporarily: that is a potential
52
+ // source of OOM crashes given large enough input, such as is common with
53
+ // Performance traces).
37
54
  const blobAsUrl = reader.result;
38
- const [, base64] = blobAsUrl.split(',', 2);
55
+ const index = blobAsUrl.indexOf(',');
56
+ const base64 = blobAsUrl.slice(index + 1);
39
57
  resolve(base64);
40
58
  };
41
59
  reader.readAsDataURL(new Blob([input]));
@@ -64,3 +64,14 @@ export function compressStream(stream) {
64
64
  const cs = new CompressionStream('gzip');
65
65
  return stream.pipeThrough(cs);
66
66
  }
67
+ export function createMonitoredStream(stream, onProgress) {
68
+ let bytesRead = 0;
69
+ const progressTransformer = new TransformStream({
70
+ transform(chunk, controller) {
71
+ bytesRead += chunk.byteLength;
72
+ onProgress(bytesRead);
73
+ controller.enqueue(chunk);
74
+ }
75
+ });
76
+ return stream.pipeThrough(progressTransformer);
77
+ }
@@ -57,7 +57,12 @@ export class ObjectWrapper {
57
57
  // new listeners.
58
58
  for (const listener of [...listeners]) {
59
59
  if (!listener.disposed) {
60
- listener.listener.call(listener.thisObject, event);
60
+ try {
61
+ listener.listener.call(listener.thisObject, event);
62
+ }
63
+ catch (err) {
64
+ console.error(`Event listener for ${String(eventType)} throw an error:`, err);
65
+ }
61
66
  }
62
67
  }
63
68
  }
@@ -263,6 +263,9 @@ export class ParsedURL {
263
263
  return '';
264
264
  }
265
265
  static extractName(url) {
266
+ if (url.endsWith('/')) {
267
+ url = url.slice(0, -1);
268
+ }
266
269
  let index = url.lastIndexOf('/');
267
270
  const pathAndQuery = index !== -1 ? url.substr(index + 1) : url;
268
271
  index = pathAndQuery.indexOf('?');
@@ -229,6 +229,12 @@ export class ResourceType {
229
229
  const regex = new RegExp('^application(.*json$|\/json\+.*)');
230
230
  return regex.test(contentType) ? 'application/json' : contentType;
231
231
  }
232
+ /**
233
+ * Checks whether the given MIME type represents JavaScript content.
234
+ */
235
+ static isJavaScriptMimeType(mimeType) {
236
+ return mimeType === 'application/javascript' || mimeType === 'text/javascript';
237
+ }
232
238
  /**
233
239
  * Adds suffixes iff the mimeType is 'text/javascript' to denote whether the JS is minified or from
234
240
  * a source map.
@@ -162,18 +162,28 @@ export class Settings {
162
162
  return this.#registry;
163
163
  }
164
164
  }
165
- export const NOOP_STORAGE = {
166
- register: () => { },
167
- set: () => { },
168
- get: () => Promise.resolve(''),
169
- remove: () => { },
170
- clear: () => { },
171
- };
165
+ export class InMemoryStorage {
166
+ #store = new Map();
167
+ register(_setting) {
168
+ }
169
+ set(key, value) {
170
+ this.#store.set(key, value);
171
+ }
172
+ get(key) {
173
+ return this.#store.get(key);
174
+ }
175
+ remove(key) {
176
+ this.#store.delete(key);
177
+ }
178
+ clear() {
179
+ this.#store.clear();
180
+ }
181
+ }
172
182
  export class SettingsStorage {
173
183
  object;
174
184
  backingStore;
175
185
  storagePrefix;
176
- constructor(object, backingStore = NOOP_STORAGE, storagePrefix = '') {
186
+ constructor(object, backingStore = new InMemoryStorage(), storagePrefix = '') {
177
187
  this.object = object;
178
188
  this.backingStore = backingStore;
179
189
  this.storagePrefix = storagePrefix;
@@ -87,6 +87,9 @@ export class InspectorFrontendHostStub {
87
87
  setInjectedScriptForOrigin(_origin, _script) {
88
88
  }
89
89
  inspectedURLChanged(url) {
90
+ if (!('document' in globalThis)) {
91
+ return;
92
+ }
90
93
  document.title = i18nString(UIStrings.devtoolsS, { PH1: url.replace(/^https?:\/\//, '') });
91
94
  }
92
95
  copyText(text) {
@@ -297,9 +300,6 @@ export class InspectorFrontendHostStub {
297
300
  devToolsFlexibleLayout: {
298
301
  verticalDrawerEnabled: true,
299
302
  },
300
- devToolsStartingStyleDebugging: {
301
- enabled: false,
302
- },
303
303
  };
304
304
  if ('hostConfigForTesting' in globalThis) {
305
305
  const { hostConfigForTesting } = globalThis;
@@ -169,7 +169,7 @@ async function fetchToString(url) {
169
169
  }
170
170
  function canBeRemoteFilePath(url) {
171
171
  try {
172
- const urlObject = new URL(url);
172
+ const urlObject = new URL(new URL(url).toString()); // Normalize first.
173
173
  return urlObject.protocol === 'file:' && urlObject.host !== '';
174
174
  }
175
175
  catch {
@@ -225,6 +225,18 @@ export class UserMetrics {
225
225
  consoleInsightTeaserFirstChunkGenerated(timeInMilliseconds) {
226
226
  InspectorFrontendHostInstance.recordPerformanceHistogram('DevTools.Insights.TeaserFirstChunkGenerationTime', timeInMilliseconds);
227
227
  }
228
+ consoleInsightTeaserAbortedAfterFirstCharacter(timeInMilliseconds) {
229
+ InspectorFrontendHostInstance.recordPerformanceHistogram('DevTools.Insights.TeaserAfterFirstCharacterAbortionTime', timeInMilliseconds);
230
+ }
231
+ consoleInsightTeaserAbortedBeforeFirstCharacter(timeInMilliseconds) {
232
+ InspectorFrontendHostInstance.recordPerformanceHistogram('DevTools.Insights.TeaserBeforeFirstCharacterAbortionTime', timeInMilliseconds);
233
+ }
234
+ consoleInsightLongTeaserGenerated(timeInMilliseconds) {
235
+ InspectorFrontendHostInstance.recordPerformanceHistogram('DevTools.Insights.LongTeaserGenerationTime', timeInMilliseconds);
236
+ }
237
+ consoleInsightShortTeaserGenerated(timeInMilliseconds) {
238
+ InspectorFrontendHostInstance.recordPerformanceHistogram('DevTools.Insights.ShortTeaserGenerationTime', timeInMilliseconds);
239
+ }
228
240
  }
229
241
  /**
230
242
  * The numeric enum values are not necessarily continuous! It is possible that
@@ -436,7 +448,11 @@ export var Action;
436
448
  Action[Action["InsightTeaserGenerationErrored"] = 194] = "InsightTeaserGenerationErrored";
437
449
  Action[Action["AiCodeGenerationSuggestionDisplayed"] = 195] = "AiCodeGenerationSuggestionDisplayed";
438
450
  Action[Action["AiCodeGenerationSuggestionAccepted"] = 196] = "AiCodeGenerationSuggestionAccepted";
439
- Action[Action["MAX_VALUE"] = 197] = "MAX_VALUE";
451
+ Action[Action["InsightTeaserModelDownloadStarted"] = 197] = "InsightTeaserModelDownloadStarted";
452
+ Action[Action["InsightTeaserModelDownloadCompleted"] = 198] = "InsightTeaserModelDownloadCompleted";
453
+ Action[Action["AiCodeGenerationError"] = 199] = "AiCodeGenerationError";
454
+ Action[Action["AiCodeGenerationRequestTriggered"] = 200] = "AiCodeGenerationRequestTriggered";
455
+ Action[Action["MAX_VALUE"] = 201] = "MAX_VALUE";
440
456
  /* eslint-enable @typescript-eslint/naming-convention */
441
457
  })(Action || (Action = {}));
442
458
  export var PanelCodes;
@@ -197,3 +197,13 @@ export function nearestIndexFromEnd(arr, predicate) {
197
197
  export function arrayDoesNotContainNullOrUndefined(arr) {
198
198
  return !arr.includes(null) && !arr.includes(undefined);
199
199
  }
200
+ export function assertArrayIsSorted(arr, compareFn) {
201
+ const comparator = compareFn || DEFAULT_COMPARATOR;
202
+ for (let i = 0; i < arr.length - 1; i++) {
203
+ const current = arr[i];
204
+ const next = arr[i + 1];
205
+ if (comparator(current, next) > 0) {
206
+ throw new Error(`Array is not sorted at index ${i}: ${JSON.stringify(current)} > ${JSON.stringify(next)}`);
207
+ }
208
+ }
209
+ }
@@ -325,26 +325,77 @@ export const compare = (a, b) => {
325
325
  }
326
326
  return 0;
327
327
  };
328
+ /** Returns a string that has no more than maxLength characters. Actual graphemes are used, not bytes. */
328
329
  export const trimMiddle = (str, maxLength) => {
330
+ // Early return for the case where there are fewer bytes than the character limit.
329
331
  if (str.length <= maxLength) {
330
- return String(str);
331
- }
332
- let leftHalf = maxLength >> 1;
333
- let rightHalf = maxLength - leftHalf - 1;
334
- if (str.codePointAt(str.length - rightHalf - 1) >= 0x10000) {
335
- --rightHalf;
336
- ++leftHalf;
332
+ return str;
333
+ }
334
+ const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
335
+ // If the max length is so small it can't fit the ellipsis, just return the ellipsis.
336
+ const ellipsis = '…';
337
+ const ellipsisLength = 1;
338
+ if (maxLength <= ellipsisLength) {
339
+ return ellipsis;
340
+ }
341
+ // Calculate how many graphemes to keep on each side.
342
+ const freeSpace = maxLength - ellipsisLength;
343
+ const leftCount = Math.ceil(freeSpace / 2);
344
+ const rightCount = Math.floor(freeSpace / 2);
345
+ let currentGraphemeCount = 0;
346
+ let leftEndIndex = 0;
347
+ // Sliding Window Buffer
348
+ // We need to know where the "Right Half" starts. Since we can't iterate backwards,
349
+ // we keep track of the start index of the last N graphemes we've seen.
350
+ const rightIndexBuffer = [];
351
+ // This function would be significantly simpler if we created an array of all the
352
+ // segments upfront, but could result in poor performance for large input strings.
353
+ for (const { segment, index } of segmenter.segment(str)) {
354
+ currentGraphemeCount++;
355
+ // Mark the byte index where the "Left Half" ends
356
+ if (currentGraphemeCount === leftCount) {
357
+ leftEndIndex = index + segment.length;
358
+ }
359
+ // Maintain the buffer for the "Right Half"
360
+ if (rightCount > 0) {
361
+ rightIndexBuffer.push(index);
362
+ if (rightIndexBuffer.length > rightCount) {
363
+ rightIndexBuffer.shift(); // Remove the oldest index to keep buffer size constant.
364
+ }
365
+ }
337
366
  }
338
- if (leftHalf > 0 && str.codePointAt(leftHalf - 1) >= 0x10000) {
339
- --leftHalf;
367
+ // If the total grapheme count didn't exceed the limit, return the original string.
368
+ if (currentGraphemeCount <= maxLength) {
369
+ return str;
340
370
  }
341
- return str.substr(0, leftHalf) + '' + str.substr(str.length - rightHalf, rightHalf);
371
+ // The first item in our buffer is exactly 'rightCount' graphemes away from the end.
372
+ const rightStartIndex = rightCount > 0 ? rightIndexBuffer[0] : str.length;
373
+ return str.slice(0, leftEndIndex) + ellipsis + str.slice(rightStartIndex);
342
374
  };
375
+ /** Returns a string that has no more than maxLength characters. Actual graphemes are used, not bytes. */
343
376
  export const trimEndWithMaxLength = (str, maxLength) => {
377
+ // Early return for the case where there are fewer bytes than the character limit.
344
378
  if (str.length <= maxLength) {
345
- return String(str);
379
+ return str;
380
+ }
381
+ const ellipsis = '…';
382
+ const ellipsisLength = 1;
383
+ const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
384
+ const iterator = segmenter.segment(str)[Symbol.iterator]();
385
+ let lastSegmentIndex = 0;
386
+ for (let i = 0; i <= maxLength - ellipsisLength; i++) {
387
+ const result = iterator.next();
388
+ if (result.done) {
389
+ return str;
390
+ }
391
+ lastSegmentIndex = result.value.index;
392
+ }
393
+ for (let i = 0; i < ellipsisLength; i++) {
394
+ if (iterator.next().done) {
395
+ return str;
396
+ }
346
397
  }
347
- return str.substr(0, maxLength - 1) + '…';
398
+ return str.slice(0, lastSegmentIndex) + ellipsis;
348
399
  };
349
400
  export const escapeForRegExp = (str) => {
350
401
  return escapeCharacters(str, SPECIAL_REGEX_CHARACTERS);
@@ -14,4 +14,5 @@ export var CDPErrorStatus;
14
14
  CDPErrorStatus[CDPErrorStatus["SERVER_ERROR"] = -32000] = "SERVER_ERROR";
15
15
  CDPErrorStatus[CDPErrorStatus["SESSION_NOT_FOUND"] = -32001] = "SESSION_NOT_FOUND";
16
16
  CDPErrorStatus[CDPErrorStatus["DEVTOOLS_STUB_ERROR"] = -32015] = "DEVTOOLS_STUB_ERROR";
17
+ CDPErrorStatus[CDPErrorStatus["DEVTOOLS_REHYDRATION_ERROR"] = -32016] = "DEVTOOLS_REHYDRATION_ERROR";
17
18
  })(CDPErrorStatus || (CDPErrorStatus = {}));
@@ -444,6 +444,7 @@ export class TargetBase {
444
444
  }
445
445
  /** These are not logged as console.error */
446
446
  const IGNORED_ERRORS = new Set([
447
+ CDPErrorStatus.DEVTOOLS_REHYDRATION_ERROR,
447
448
  CDPErrorStatus.DEVTOOLS_STUB_ERROR,
448
449
  CDPErrorStatus.SERVER_ERROR,
449
450
  CDPErrorStatus.SESSION_NOT_FOUND,
@@ -491,7 +492,9 @@ class AgentPrototype {
491
492
  if ('result' in response) {
492
493
  return { ...response.result, getError: () => undefined };
493
494
  }
494
- return { getError: () => undefined };
495
+ return {
496
+ getError: () => `Command ${method} returned neither result nor an error, params: ${JSON.stringify(request, undefined, 2)}`,
497
+ };
495
498
  });
496
499
  }
497
500
  }
@@ -474,10 +474,10 @@ export class CSSMatchedStyles {
474
474
  // Now that we've built the arrays of NodeCascades for each pseudo type, convert them into
475
475
  // DOMInheritanceCascades.
476
476
  for (const [pseudoType, nodeCascade] of pseudoCascades.entries()) {
477
- pseudoInheritanceCascades.set(pseudoType, new DOMInheritanceCascade(this, nodeCascade, this.#registeredProperties));
477
+ pseudoInheritanceCascades.set(pseudoType, new DOMInheritanceCascade(this, nodeCascade, this.#registeredProperties, this.#mainDOMCascade));
478
478
  }
479
479
  for (const [highlightName, nodeCascade] of customHighlightPseudoCascades.entries()) {
480
- customHighlightPseudoInheritanceCascades.set(highlightName, new DOMInheritanceCascade(this, nodeCascade, this.#registeredProperties));
480
+ customHighlightPseudoInheritanceCascades.set(highlightName, new DOMInheritanceCascade(this, nodeCascade, this.#registeredProperties, this.#mainDOMCascade));
481
481
  }
482
482
  return [pseudoInheritanceCascades, customHighlightPseudoInheritanceCascades];
483
483
  }
@@ -730,18 +730,18 @@ export class CSSMatchedStyles {
730
730
  }
731
731
  }
732
732
  class NodeCascade {
733
+ isHighlightPseudoCascade;
733
734
  #matchedStyles;
734
735
  styles;
735
736
  #isInherited;
736
- #isHighlightPseudoCascade;
737
737
  propertiesState = new Map();
738
738
  activeProperties = new Map();
739
739
  #node;
740
740
  constructor(matchedStyles, styles, node, isInherited, isHighlightPseudoCascade = false) {
741
+ this.isHighlightPseudoCascade = isHighlightPseudoCascade;
741
742
  this.#matchedStyles = matchedStyles;
742
743
  this.styles = styles;
743
744
  this.#isInherited = isInherited;
744
- this.#isHighlightPseudoCascade = isHighlightPseudoCascade;
745
745
  this.#node = node;
746
746
  }
747
747
  computeActiveProperties() {
@@ -760,9 +760,17 @@ class NodeCascade {
760
760
  for (const property of style.allProperties()) {
761
761
  // Do not pick non-inherited properties from inherited styles.
762
762
  const metadata = cssMetadata();
763
- // All properties are inherited for highlight pseudos.
764
- if (this.#isInherited && !this.#isHighlightPseudoCascade && !metadata.isPropertyInherited(property.name)) {
765
- continue;
763
+ if (this.#isInherited) {
764
+ if (this.isHighlightPseudoCascade) {
765
+ // All properties are inherited for highlight pseudos, but custom
766
+ // variables do not come from the inherited pseudo elements.
767
+ if (property.name.startsWith('--')) {
768
+ continue;
769
+ }
770
+ }
771
+ else if (!metadata.isPropertyInherited(property.name)) {
772
+ continue;
773
+ }
766
774
  }
767
775
  // When a property does not have a range in an otherwise ranged CSSStyleDeclaration,
768
776
  // we consider it as a non-leading property (see computeLeadingProperties()), and most
@@ -920,13 +928,24 @@ class DOMInheritanceCascade {
920
928
  #nodeCascades;
921
929
  #registeredProperties;
922
930
  #matchedStyles;
923
- constructor(matchedStyles, nodeCascades, registeredProperties) {
931
+ #fallbackCascade = null;
932
+ #styles = [];
933
+ constructor(matchedStyles, nodeCascades, registeredProperties, fallbackCascade = null) {
924
934
  this.#nodeCascades = nodeCascades;
925
935
  this.#matchedStyles = matchedStyles;
926
936
  this.#registeredProperties = registeredProperties;
937
+ this.#fallbackCascade = fallbackCascade;
927
938
  for (const nodeCascade of nodeCascades) {
928
939
  for (const style of nodeCascade.styles) {
929
940
  this.#styleToNodeCascade.set(style, nodeCascade);
941
+ this.#styles.push(style);
942
+ }
943
+ }
944
+ if (fallbackCascade) {
945
+ for (const [style, nodeCascade] of fallbackCascade.#styleToNodeCascade) {
946
+ if (!this.#styles.includes(style)) {
947
+ this.#styleToNodeCascade.set(style, nodeCascade);
948
+ }
930
949
  }
931
950
  }
932
951
  }
@@ -981,6 +1000,9 @@ class DOMInheritanceCascade {
981
1000
  }
982
1001
  }
983
1002
  }
1003
+ if (this.#fallbackCascade && (!nodeCascade.isHighlightPseudoCascade || property.name.startsWith('--'))) {
1004
+ return this.#fallbackCascade.resolveProperty(property.name, property.ownerStyle);
1005
+ }
984
1006
  return null;
985
1007
  }
986
1008
  #findPropertyInParentCascadeIfInherited(property) {
@@ -1224,7 +1246,7 @@ class DOMInheritanceCascade {
1224
1246
  }
1225
1247
  }
1226
1248
  styles() {
1227
- return Array.from(this.#styleToNodeCascade.keys());
1249
+ return this.#styles;
1228
1250
  }
1229
1251
  propertyState(property) {
1230
1252
  this.ensureInitialized();
@@ -1289,6 +1311,19 @@ class DOMInheritanceCascade {
1289
1311
  const initialValue = rule.initialValue();
1290
1312
  accumulatedCSSVariables.set(rule.propertyName(), initialValue !== null ? { value: initialValue, declaration: new CSSValueSource(rule) } : null);
1291
1313
  }
1314
+ if (this.#fallbackCascade) {
1315
+ this.#fallbackCascade.ensureInitialized();
1316
+ for (const [cascade, available] of this.#fallbackCascade.#availableCSSVariables) {
1317
+ this.#availableCSSVariables.set(cascade, available);
1318
+ }
1319
+ for (const [cascade, computed] of this.#fallbackCascade.#computedCSSVariables) {
1320
+ this.#computedCSSVariables.set(cascade, computed);
1321
+ }
1322
+ for (const [key, value] of this.#fallbackCascade.#availableCSSVariables.get(this.#fallbackCascade.#nodeCascades[0]) ??
1323
+ []) {
1324
+ accumulatedCSSVariables.set(key, value);
1325
+ }
1326
+ }
1292
1327
  for (let i = this.#nodeCascades.length - 1; i >= 0; --i) {
1293
1328
  const nodeCascade = this.#nodeCascades[i];
1294
1329
  const variableNames = [];
@@ -526,7 +526,7 @@ const extraPropertyValues = new Map([
526
526
  ['background-repeat', new Set(['repeat', 'repeat-x', 'repeat-y', 'no-repeat', 'space', 'round'])],
527
527
  ['content', new Set(['normal', 'close-quote', 'no-close-quote', 'no-open-quote', 'open-quote'])],
528
528
  ['baseline-shift', new Set(['baseline'])],
529
- ['max-height', new Set(['min-content', 'max-content', '-webkit-fill-available', 'fit-content'])],
529
+ ['max-height', new Set(['min-content', 'max-content', '-webkit-fill-available', 'fit-content', 'stretch'])],
530
530
  ['color', new Set(['black'])],
531
531
  ['background-color', new Set(['white'])],
532
532
  ['box-shadow', new Set(['inset'])],
@@ -600,7 +600,7 @@ const extraPropertyValues = new Map([
600
600
  ]),
601
601
  ],
602
602
  ['zoom', new Set(['normal'])],
603
- ['max-width', new Set(['min-content', 'max-content', '-webkit-fill-available', 'fit-content'])],
603
+ ['max-width', new Set(['min-content', 'max-content', '-webkit-fill-available', 'fit-content', 'stretch'])],
604
604
  ['-webkit-font-smoothing', new Set(['antialiased', 'subpixel-antialiased'])],
605
605
  [
606
606
  'border',
@@ -991,7 +991,7 @@ const extraPropertyValues = new Map([
991
991
  ]),
992
992
  ],
993
993
  ['flex-flow', new Set(['nowrap', 'row', 'row-reverse', 'column', 'column-reverse', 'wrap', 'wrap-reverse'])],
994
- ['height', new Set(['-webkit-fill-available'])],
994
+ ['height', new Set(['-webkit-fill-available', 'stretch'])],
995
995
  ['inline-size', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
996
996
  [
997
997
  'list-style',
@@ -1058,9 +1058,9 @@ const extraPropertyValues = new Map([
1058
1058
  ['max-block-size', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
1059
1059
  ['max-inline-size', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
1060
1060
  ['min-block-size', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
1061
- ['min-height', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
1061
+ ['min-height', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content', 'stretch'])],
1062
1062
  ['min-inline-size', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
1063
- ['min-width', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content'])],
1063
+ ['min-width', new Set(['-webkit-fill-available', 'min-content', 'max-content', 'fit-content', 'stretch'])],
1064
1064
  ['object-position', new Set(['top', 'bottom', 'left', 'right', 'center'])],
1065
1065
  ['shape-outside', new Set(['border-box', 'content-box', 'padding-box', 'margin-box'])],
1066
1066
  [
@@ -1222,7 +1222,7 @@ const extraPropertyValues = new Map([
1222
1222
  ['-webkit-text-stroke-width', new Set(['medium', 'thick', 'thin'])],
1223
1223
  ['-webkit-transform-origin-x', new Set(['left', 'right', 'center'])],
1224
1224
  ['-webkit-transform-origin-y', new Set(['top', 'bottom', 'center'])],
1225
- ['width', new Set(['-webkit-fill-available'])],
1225
+ ['width', new Set(['-webkit-fill-available', 'stretch'])],
1226
1226
  ['contain-intrinsic-width', new Set(['auto none', 'auto 100px'])],
1227
1227
  ['contain-intrinsic-height', new Set(['auto none', 'auto 100px'])],
1228
1228
  ['contain-intrinsic-size', new Set(['auto none', 'auto 100px'])],
@@ -317,7 +317,7 @@ export class CSSModel extends SDKModel {
317
317
  isGrid,
318
318
  isSubgrid,
319
319
  isGridLanes,
320
- isContainer,
320
+ containerType: isContainer ? containerType : undefined,
321
321
  hasScroll,
322
322
  };
323
323
  }