@yezack/chrome-devtools-mcp-108 0.0.0-stage → 1.10.2

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 (360) hide show
  1. package/FORK-NOTICE.md +45 -0
  2. package/LICENSE +202 -0
  3. package/README.md +45 -2
  4. package/build/src/BrowserManager.js +401 -0
  5. package/build/src/McpContext.js +642 -0
  6. package/build/src/McpPage.js +850 -0
  7. package/build/src/McpResponse.js +1086 -0
  8. package/build/src/SlimMcpResponse.js +19 -0
  9. package/build/src/TextSnapshot.js +315 -0
  10. package/build/src/ToolHandler.js +322 -0
  11. package/build/src/bin/check-latest-version.js +51 -0
  12. package/build/src/bin/chrome-devtools-mcp-main.js +77 -0
  13. package/build/src/bin/chrome-devtools-mcp.js +23 -0
  14. package/build/src/bin/chrome-devtools.js +222 -0
  15. package/build/src/collectors/PageCollector.js +291 -0
  16. package/build/src/collectors/ServiceWorkerCollector.js +171 -0
  17. package/build/src/config/browser-options.js +125 -0
  18. package/build/src/config/category-options.js +89 -0
  19. package/build/src/config/cli-commands.js +26 -0
  20. package/build/src/config/cli-options.js +1473 -0
  21. package/build/src/config/mcp-options.js +417 -0
  22. package/build/src/daemon/client.js +221 -0
  23. package/build/src/daemon/daemon.js +266 -0
  24. package/build/src/daemon/types.js +7 -0
  25. package/build/src/daemon/utils.js +136 -0
  26. package/build/src/devtools/DevToolsCommentBridge.js +91 -0
  27. package/build/src/devtools/DevtoolsUtils.js +307 -0
  28. package/build/src/devtools/McpHostBindingAdapter.js +165 -0
  29. package/build/src/devtools/issueDescriptions.js +42 -0
  30. package/build/src/formatters/CommentFormatter.js +82 -0
  31. package/build/src/formatters/ConsoleFormatter.js +321 -0
  32. package/build/src/formatters/CssFormatter.js +812 -0
  33. package/build/src/formatters/HeapSnapshotFormatter.js +185 -0
  34. package/build/src/formatters/IssueFormatter.js +193 -0
  35. package/build/src/formatters/NetworkFormatter.js +241 -0
  36. package/build/src/formatters/SnapshotFormatter.js +135 -0
  37. package/build/src/index.js +237 -0
  38. package/build/src/processors/ChunkedTraceParser.js +361 -0
  39. package/build/src/processors/HeapSnapshotManager.js +270 -0
  40. package/build/src/processors/PerformanceTrace.js +132 -0
  41. package/build/src/telemetry/ClearcutLogger.js +242 -0
  42. package/build/src/telemetry/WatchdogClient.js +61 -0
  43. package/build/src/telemetry/errors.js +18 -0
  44. package/build/src/telemetry/flagUtils.js +90 -0
  45. package/build/src/telemetry/metricsRegistry.js +85 -0
  46. package/build/src/telemetry/persistence.js +82 -0
  47. package/build/src/telemetry/transformation.js +233 -0
  48. package/build/src/telemetry/types.js +36 -0
  49. package/build/src/telemetry/watchdog/ClearcutSender.js +205 -0
  50. package/build/src/telemetry/watchdog/main.js +128 -0
  51. package/build/src/third_party/THIRD_PARTY_NOTICES +4077 -0
  52. package/build/src/third_party/bundled-packages.json +12 -0
  53. package/build/src/third_party/devtools-formatter-worker.js +15494 -0
  54. package/build/src/third_party/devtools-heap-snapshot-worker.js +10979 -0
  55. package/build/src/third_party/index.js +200978 -0
  56. package/build/src/third_party/issue-descriptions/CoepCoopSandboxedIframeCannotNavigateToCoopPage.md +4 -0
  57. package/build/src/third_party/issue-descriptions/CoepCorpNotSameOrigin.md +8 -0
  58. package/build/src/third_party/issue-descriptions/CoepCorpNotSameOriginAfterDefaultedToSameOriginByCoep.md +18 -0
  59. package/build/src/third_party/issue-descriptions/CoepCorpNotSameSite.md +7 -0
  60. package/build/src/third_party/issue-descriptions/CoepFrameResourceNeedsCoepHeader.md +10 -0
  61. package/build/src/third_party/issue-descriptions/CompatibilityModeQuirks.md +5 -0
  62. package/build/src/third_party/issue-descriptions/CookieAttributeValueExceedsMaxSize.md +5 -0
  63. package/build/src/third_party/issue-descriptions/LowTextContrast.md +5 -0
  64. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorRead.md +8 -0
  65. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorSet.md +8 -0
  66. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnRead.md +8 -0
  67. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnSet.md +8 -0
  68. package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeRead.md +9 -0
  69. package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeSet.md +9 -0
  70. package/build/src/third_party/issue-descriptions/bounceTrackingMitigations.md +3 -0
  71. package/build/src/third_party/issue-descriptions/clientHintMetaTagAllowListInvalidOrigin.md +4 -0
  72. package/build/src/third_party/issue-descriptions/clientHintMetaTagModifiedHTML.md +4 -0
  73. package/build/src/third_party/issue-descriptions/connectionAllowlistEmbeddingRequirementNotSatisfied.md +26 -0
  74. package/build/src/third_party/issue-descriptions/connectionAllowlistIFrameAttributeLoosensEmbeddingRequirement.md +19 -0
  75. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowConnectionAllowlistFrom.md +21 -0
  76. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowlistItemType.md +12 -0
  77. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidHeader.md +12 -0
  78. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidUrlPattern.md +8 -0
  79. package/build/src/third_party/issue-descriptions/connectionAllowlistItemNotInnerList.md +12 -0
  80. package/build/src/third_party/issue-descriptions/connectionAllowlistMoreThanOneList.md +7 -0
  81. package/build/src/third_party/issue-descriptions/connectionAllowlistReportingEndpointNotToken.md +10 -0
  82. package/build/src/third_party/issue-descriptions/cookieCrossSiteRedirectDowngrade.md +12 -0
  83. package/build/src/third_party/issue-descriptions/cookieExcludeDomainNonAscii.md +11 -0
  84. package/build/src/third_party/issue-descriptions/cookieExcludePortMismatch.md +8 -0
  85. package/build/src/third_party/issue-descriptions/cookieExcludeSchemeMismatch.md +7 -0
  86. package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutRead.md +6 -0
  87. package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutSet.md +6 -0
  88. package/build/src/third_party/issue-descriptions/cookieWarnDomainNonAscii.md +11 -0
  89. package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantRead.md +4 -0
  90. package/build/src/third_party/issue-descriptions/cookieWarnMetadataGrantSet.md +4 -0
  91. package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutRead.md +6 -0
  92. package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutSet.md +6 -0
  93. package/build/src/third_party/issue-descriptions/corsAllowCredentialsRequired.md +6 -0
  94. package/build/src/third_party/issue-descriptions/corsDisabledScheme.md +7 -0
  95. package/build/src/third_party/issue-descriptions/corsDisallowedByMode.md +7 -0
  96. package/build/src/third_party/issue-descriptions/corsHeaderDisallowedByPreflightResponse.md +5 -0
  97. package/build/src/third_party/issue-descriptions/corsInvalidHeaderValues.md +7 -0
  98. package/build/src/third_party/issue-descriptions/corsLocalNetworkAccessPermissionDenied.md +19 -0
  99. package/build/src/third_party/issue-descriptions/corsMethodDisallowedByPreflightResponse.md +5 -0
  100. package/build/src/third_party/issue-descriptions/corsNoCorsRedirectModeNotFollow.md +5 -0
  101. package/build/src/third_party/issue-descriptions/corsOriginMismatch.md +6 -0
  102. package/build/src/third_party/issue-descriptions/corsPreflightResponseInvalid.md +5 -0
  103. package/build/src/third_party/issue-descriptions/corsRedirectContainsCredentials.md +5 -0
  104. package/build/src/third_party/issue-descriptions/corsWildcardOriginNotAllowed.md +9 -0
  105. package/build/src/third_party/issue-descriptions/cspEvalViolation.md +9 -0
  106. package/build/src/third_party/issue-descriptions/cspInlineViolation.md +10 -0
  107. package/build/src/third_party/issue-descriptions/cspTrustedTypesPolicyViolation.md +5 -0
  108. package/build/src/third_party/issue-descriptions/cspTrustedTypesSinkViolation.md +8 -0
  109. package/build/src/third_party/issue-descriptions/cspURLViolation.md +10 -0
  110. package/build/src/third_party/issue-descriptions/deprecation.md +3 -0
  111. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsEmptyList.md +1 -0
  112. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsHttpNotFound.md +1 -0
  113. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidContentType.md +1 -0
  114. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidResponse.md +1 -0
  115. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsNoResponse.md +1 -0
  116. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
  117. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
  118. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownHttpNotFound.md +1 -0
  119. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidContentType.md +1 -0
  120. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidResponse.md +1 -0
  121. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownNoResponse.md +1 -0
  122. package/build/src/third_party/issue-descriptions/emailVerificationRequestInvalidEmail.md +1 -0
  123. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksHttpNotFound.md +1 -0
  124. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksInvalidResponse.md +1 -0
  125. package/build/src/third_party/issue-descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
  126. package/build/src/third_party/issue-descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
  127. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
  128. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
  129. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
  130. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
  131. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
  132. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
  133. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidAudience.md +1 -0
  134. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidIssuedAt.md +1 -0
  135. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidNonce.md +1 -0
  136. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidSdHash.md +1 -0
  137. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidTyp.md +1 -0
  138. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingAud.md +1 -0
  139. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingCnf.md +1 -0
  140. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingIat.md +1 -0
  141. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingNonce.md +1 -0
  142. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingSdHash.md +1 -0
  143. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbSignatureFailed.md +1 -0
  144. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmail.md +1 -0
  145. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmailVerified.md +1 -0
  146. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidHolderKey.md +1 -0
  147. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuedAt.md +1 -0
  148. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuer.md +1 -0
  149. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtJwksMissingKeys.md +1 -0
  150. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingCnf.md +1 -0
  151. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingEmail.md +1 -0
  152. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIat.md +1 -0
  153. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIss.md +1 -0
  154. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtSignatureFailed.md +1 -0
  155. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtUnsupportedHeaderAlg.md +1 -0
  156. package/build/src/third_party/issue-descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
  157. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
  158. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
  159. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
  160. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
  161. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
  162. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
  163. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
  164. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
  165. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
  166. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
  167. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsBlockedByConnectionAllowlist.md +1 -0
  168. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsHttpNotFound.md +1 -0
  169. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsInvalidResponse.md +1 -0
  170. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsNoResponse.md +1 -0
  171. package/build/src/third_party/issue-descriptions/federatedAuthRequestApprovalDeclined.md +1 -0
  172. package/build/src/third_party/issue-descriptions/federatedAuthRequestCanceled.md +1 -0
  173. package/build/src/third_party/issue-descriptions/federatedAuthRequestConfigBlockedByConnectionAllowlist.md +1 -0
  174. package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorFetchingSignin.md +1 -0
  175. package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorIdToken.md +1 -0
  176. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenBlockedByConnectionAllowlist.md +1 -0
  177. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenHttpNotFound.md +1 -0
  178. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -0
  179. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -0
  180. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -0
  181. package/build/src/third_party/issue-descriptions/federatedAuthRequestInvalidSigninResponse.md +1 -0
  182. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestHttpNotFound.md +1 -0
  183. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestInvalidResponse.md +1 -0
  184. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestNoResponse.md +1 -0
  185. package/build/src/third_party/issue-descriptions/federatedAuthRequestTooManyRequests.md +1 -0
  186. package/build/src/third_party/issue-descriptions/federatedAuthRequestWellKnownBlockedByConnectionAllowlist.md +1 -0
  187. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidAccountsResponse.md +1 -0
  188. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidConfigOrWellKnown.md +1 -0
  189. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoAccountSharingPermission.md +1 -0
  190. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoApiPermission.md +1 -0
  191. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoReturningUserFromFetchedAccounts.md +1 -0
  192. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotIframe.md +1 -0
  193. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotPotentiallyTrustworthy.md +1 -0
  194. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSameOrigin.md +1 -0
  195. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSignedInWithIdp.md +1 -0
  196. package/build/src/third_party/issue-descriptions/fetchingPartitionedBlobURL.md +7 -0
  197. package/build/src/third_party/issue-descriptions/genericBackUINavigationWouldSkipAd.md +4 -0
  198. package/build/src/third_party/issue-descriptions/genericFormAriaLabelledByToNonExistingIdError.md +8 -0
  199. package/build/src/third_party/issue-descriptions/genericFormAutocompleteAttributeEmptyError.md +5 -0
  200. package/build/src/third_party/issue-descriptions/genericFormDuplicateIdForInputError.md +5 -0
  201. package/build/src/third_party/issue-descriptions/genericFormEmptyIdAndNameAttributesForInputError.md +5 -0
  202. package/build/src/third_party/issue-descriptions/genericFormInputAssignedAutocompleteValueToIdOrNameAttributeError.md +5 -0
  203. package/build/src/third_party/issue-descriptions/genericFormInputHasWrongButWellIntendedAutocompleteValueError.md +5 -0
  204. package/build/src/third_party/issue-descriptions/genericFormInputWithNoLabelError.md +5 -0
  205. package/build/src/third_party/issue-descriptions/genericFormLabelForMatchesNonExistingIdError.md +5 -0
  206. package/build/src/third_party/issue-descriptions/genericFormLabelForNameError.md +5 -0
  207. package/build/src/third_party/issue-descriptions/genericFormLabelHasNeitherForNorNestedInputError.md +5 -0
  208. package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolDescription.md +5 -0
  209. package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +5 -0
  210. package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +5 -0
  211. package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingTitleAndDescription.md +5 -0
  212. package/build/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +5 -0
  213. package/build/src/third_party/issue-descriptions/genericNavigationEntryMarkedSkippable.md +7 -0
  214. package/build/src/third_party/issue-descriptions/genericResponseWasBlockedByORB.md +4 -0
  215. package/build/src/third_party/issue-descriptions/heavyAd.md +10 -0
  216. package/build/src/third_party/issue-descriptions/lazyLoadImageZeroSize.md +7 -0
  217. package/build/src/third_party/issue-descriptions/mixedContent.md +5 -0
  218. package/build/src/third_party/issue-descriptions/navigatingPartitionedBlobURL.md +5 -0
  219. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabled.md +7 -0
  220. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluder.md +9 -0
  221. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluderParent.md +9 -0
  222. package/build/src/third_party/issue-descriptions/permissionElementCspFrameAncestorsMissing.md +5 -0
  223. package/build/src/third_party/issue-descriptions/permissionElementFencedFrameDisallowed.md +5 -0
  224. package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooLarge.md +5 -0
  225. package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooSmall.md +5 -0
  226. package/build/src/third_party/issue-descriptions/permissionElementGeolocationDeprecated.md +5 -0
  227. package/build/src/third_party/issue-descriptions/permissionElementInsetBoxShadowUnsupported.md +5 -0
  228. package/build/src/third_party/issue-descriptions/permissionElementInvalidDisplayStyle.md +5 -0
  229. package/build/src/third_party/issue-descriptions/permissionElementInvalidSizeValue.md +5 -0
  230. package/build/src/third_party/issue-descriptions/permissionElementInvalidType.md +5 -0
  231. package/build/src/third_party/issue-descriptions/permissionElementInvalidTypeActivation.md +5 -0
  232. package/build/src/third_party/issue-descriptions/permissionElementLowContrast.md +5 -0
  233. package/build/src/third_party/issue-descriptions/permissionElementNonOpaqueColor.md +5 -0
  234. package/build/src/third_party/issue-descriptions/permissionElementPaddingBottomUnsupported.md +6 -0
  235. package/build/src/third_party/issue-descriptions/permissionElementPaddingRightUnsupported.md +6 -0
  236. package/build/src/third_party/issue-descriptions/permissionElementPermissionsPolicyBlocked.md +5 -0
  237. package/build/src/third_party/issue-descriptions/permissionElementRegistrationFailed.md +5 -0
  238. package/build/src/third_party/issue-descriptions/permissionElementRequestInProgress.md +5 -0
  239. package/build/src/third_party/issue-descriptions/permissionElementSecurityChecksFailed.md +5 -0
  240. package/build/src/third_party/issue-descriptions/permissionElementTypeNotSupported.md +5 -0
  241. package/build/src/third_party/issue-descriptions/permissionElementUntrustedEvent.md +7 -0
  242. package/build/src/third_party/issue-descriptions/placeholderDescriptionForInvisibleIssues.md +3 -0
  243. package/build/src/third_party/issue-descriptions/propertyRuleInvalidNameIssue.md +3 -0
  244. package/build/src/third_party/issue-descriptions/propertyRuleIssue.md +7 -0
  245. package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedOptGroupChild.md +7 -0
  246. package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedSelectChild.md +7 -0
  247. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentAttributesSelectDescendant.md +3 -0
  248. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentLegendChild.md +3 -0
  249. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentOptionChild.md +3 -0
  250. package/build/src/third_party/issue-descriptions/selectElementAccessibilityNonPhrasingContentOptionChild.md +3 -0
  251. package/build/src/third_party/issue-descriptions/selectivePermissionsIntervention.md +7 -0
  252. package/build/src/third_party/issue-descriptions/sharedArrayBuffer.md +7 -0
  253. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +1 -0
  254. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorDictionaryLoadFailure.md +3 -0
  255. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorMatchingDictionaryNotUsed.md +3 -0
  256. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md +1 -0
  257. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorCossOriginNoCorsRequest.md +1 -0
  258. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorDisallowedBySettings.md +1 -0
  259. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorExpiredResponse.md +3 -0
  260. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorFeatureDisabled.md +3 -0
  261. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInsufficientResources.md +1 -0
  262. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidMatchField.md +1 -0
  263. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidStructuredHeader.md +1 -0
  264. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidTTLField.md +1 -0
  265. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNavigationRequest.md +3 -0
  266. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNoMatchField.md +1 -0
  267. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonIntegerTTLField.md +1 -0
  268. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonListMatchDestField.md +1 -0
  269. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonSecureContext.md +3 -0
  270. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringIdField.md +1 -0
  271. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringInMatchDestList.md +1 -0
  272. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonStringMatchField.md +1 -0
  273. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNonTokenTypeField.md +1 -0
  274. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorRequestAborted.md +1 -0
  275. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorShuttingDown.md +1 -0
  276. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorTooLongIdField.md +3 -0
  277. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorUnsupportedType.md +3 -0
  278. package/build/src/third_party/issue-descriptions/sriInvalidSignatureHeader.md +14 -0
  279. package/build/src/third_party/issue-descriptions/sriInvalidSignatureInputHeader.md +15 -0
  280. package/build/src/third_party/issue-descriptions/sriMissingSignatureHeader.md +8 -0
  281. package/build/src/third_party/issue-descriptions/sriMissingSignatureInputHeader.md +7 -0
  282. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsIncorrectLength.md +11 -0
  283. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsNotByteSequence.md +14 -0
  284. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsParameterized.md +15 -0
  285. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentName.md +8 -0
  286. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentType.md +13 -0
  287. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidDerivedComponentParameter.md +4 -0
  288. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidHeaderComponentParameter.md +5 -0
  289. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidParameter.md +11 -0
  290. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderKeyIdLength.md +12 -0
  291. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingLabel.md +6 -0
  292. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingRequiredParameters.md +8 -0
  293. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueMissingComponents.md +11 -0
  294. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueNotInnerList.md +11 -0
  295. package/build/src/third_party/issue-descriptions/sriValidationFailedIntegrityMismatch.md +10 -0
  296. package/build/src/third_party/issue-descriptions/sriValidationFailedInvalidLength.md +5 -0
  297. package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureExpired.md +6 -0
  298. package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureMismatch.md +11 -0
  299. package/build/src/third_party/issue-descriptions/stylesheetLateImport.md +4 -0
  300. package/build/src/third_party/issue-descriptions/stylesheetRequestFailed.md +3 -0
  301. package/build/src/third_party/issue-descriptions/summaryElementAccessibilityInteractiveContentSummaryDescendant.md +3 -0
  302. package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestLength.md +12 -0
  303. package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestType.md +17 -0
  304. package/build/src/third_party/issue-descriptions/unencodedDigestMalformedDictionary.md +14 -0
  305. package/build/src/third_party/issue-descriptions/unencodedDigestUnknownAlgorithm.md +15 -0
  306. package/build/src/third_party/issue-descriptions/webInstallManifestMissingId.md +3 -0
  307. package/build/src/third_party/issue-descriptions/webInstallManifestMissingNameOrShortName.md +3 -0
  308. package/build/src/third_party/issue-descriptions/webInstallManifestParsingOrNetworkError.md +3 -0
  309. package/build/src/third_party/issue-descriptions/webInstallNoManifest.md +3 -0
  310. package/build/src/third_party/issue-descriptions/webInstallStartUrlInvalid.md +3 -0
  311. package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +58435 -0
  312. package/build/src/tools/ToolDefinition.js +80 -0
  313. package/build/src/tools/categories.js +33 -0
  314. package/build/src/tools/comments.js +169 -0
  315. package/build/src/tools/console.js +104 -0
  316. package/build/src/tools/css.js +45 -0
  317. package/build/src/tools/emulation.js +84 -0
  318. package/build/src/tools/extensions.js +103 -0
  319. package/build/src/tools/input.js +652 -0
  320. package/build/src/tools/lighthouse.js +149 -0
  321. package/build/src/tools/memory.js +424 -0
  322. package/build/src/tools/network.js +128 -0
  323. package/build/src/tools/pages.js +363 -0
  324. package/build/src/tools/performance.js +212 -0
  325. package/build/src/tools/pwa.js +128 -0
  326. package/build/src/tools/screencast.js +119 -0
  327. package/build/src/tools/screenshot.js +277 -0
  328. package/build/src/tools/script.js +232 -0
  329. package/build/src/tools/slim/tools.js +96 -0
  330. package/build/src/tools/snapshot.js +63 -0
  331. package/build/src/tools/thirdPartyDeveloper.js +85 -0
  332. package/build/src/tools/tools.js +55 -0
  333. package/build/src/tools/webmcp.js +66 -0
  334. package/build/src/types.js +10 -0
  335. package/build/src/utils/WaitForHelper.js +316 -0
  336. package/build/src/utils/bytes.js +105 -0
  337. package/build/src/utils/check-for-updates.js +75 -0
  338. package/build/src/utils/files.js +57 -0
  339. package/build/src/utils/id.js +16 -0
  340. package/build/src/utils/keyboard.js +297 -0
  341. package/build/src/utils/logger.js +52 -0
  342. package/build/src/utils/pagination.js +50 -0
  343. package/build/src/utils/polyfill.js +11 -0
  344. package/build/src/utils/url.js +116 -0
  345. package/build/src/version.js +10 -0
  346. package/package.json +41 -4
  347. package/skills/a11y-debugging/SKILL.md +91 -0
  348. package/skills/a11y-debugging/references/a11y-snippets.md +92 -0
  349. package/skills/chrome-devtools/SKILL.md +74 -0
  350. package/skills/chrome-devtools-cli/SKILL.md +194 -0
  351. package/skills/chrome-devtools-cli/references/installation.md +14 -0
  352. package/skills/cookie-debugging/SKILL.md +149 -0
  353. package/skills/debug-optimize-lcp/SKILL.md +121 -0
  354. package/skills/debug-optimize-lcp/references/elements-and-size.md +27 -0
  355. package/skills/debug-optimize-lcp/references/lcp-breakdown.md +23 -0
  356. package/skills/debug-optimize-lcp/references/lcp-snippets.md +79 -0
  357. package/skills/debug-optimize-lcp/references/optimization-strategies.md +38 -0
  358. package/skills/memory-leak-debugging/SKILL.md +58 -0
  359. package/skills/memory-leak-debugging/references/common-leaks.md +33 -0
  360. package/skills/troubleshooting/SKILL.md +99 -0
@@ -0,0 +1,361 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ const DEFAULT_EVENTS_PER_BATCH = 10_000;
7
+ const DEFAULT_MAX_BATCH_BYTES = 32 * 1024 * 1024;
8
+ // ASCII character byte constants used by the state machine.
9
+ // All values are strictly less than 0x80 (standard ASCII).
10
+ // In UTF-8 encoding, multi-byte code units only contain bytes from 0x80 through 0xFF.
11
+ // Therefore, scanning for these byte values will never match bytes inside multi-byte characters.
12
+ const BYTE_QUOTE = 0x22;
13
+ const BYTE_BACKSLASH = 0x5c;
14
+ const BYTE_OPEN_BRACE = 0x7b;
15
+ const BYTE_CLOSE_BRACE = 0x7d;
16
+ const BYTE_OPEN_BRACKET = 0x5b;
17
+ const BYTE_CLOSE_BRACKET = 0x5d;
18
+ const BYTE_COLON = 0x3a;
19
+ const BYTE_COMMA = 0x2c;
20
+ /**
21
+ * Advances past any RFC 8259 JSON whitespace bytes.
22
+ *
23
+ * @param buffer - The trace byte buffer to inspect.
24
+ * @param start - The buffer index where scanning begins.
25
+ * @returns The index of the first non-whitespace byte, or the buffer length if the buffer ends.
26
+ */
27
+ function skipWhitespace(buffer, start) {
28
+ let i = start;
29
+ while (i < buffer.length) {
30
+ const byte = buffer[i];
31
+ if (byte !== 0x20 && byte !== 0x09 && byte !== 0x0a && byte !== 0x0d) {
32
+ break;
33
+ }
34
+ i++;
35
+ }
36
+ return i;
37
+ }
38
+ /**
39
+ * Scans past a JSON string starting at the opening quotation mark.
40
+ *
41
+ * @param buffer - The trace byte buffer to scan.
42
+ * @param startQuotePos - The buffer index of the opening quotation mark.
43
+ * @returns The index immediately following the closing quotation mark.
44
+ * @throws {SyntaxError} If the string is unterminated before the end of the buffer.
45
+ */
46
+ function skipString(buffer, startQuotePos) {
47
+ let pos = startQuotePos + 1;
48
+ while (pos < buffer.length) {
49
+ const byte = buffer[pos];
50
+ if (byte === BYTE_BACKSLASH) {
51
+ if (pos + 1 >= buffer.length) {
52
+ throw new SyntaxError('Unterminated string in JSON');
53
+ }
54
+ pos += 2;
55
+ continue;
56
+ }
57
+ if (byte === BYTE_QUOTE) {
58
+ return pos + 1;
59
+ }
60
+ pos++;
61
+ }
62
+ throw new SyntaxError('Unterminated string in JSON');
63
+ }
64
+ /**
65
+ * Scans past a complete JSON value starting at the specified buffer position.
66
+ * Skips strings, compound objects, arrays, and primitive values without parsing them into memory.
67
+ *
68
+ * @param buffer - The trace byte buffer to scan.
69
+ * @param startPos - The buffer index where the value begins.
70
+ * @returns The index immediately following the skipped JSON value.
71
+ * @throws {SyntaxError} If the value contains unbalanced delimiters, unterminated strings, or empty primitive tokens.
72
+ */
73
+ function skipValue(buffer, startPos) {
74
+ let pos = skipWhitespace(buffer, startPos);
75
+ if (pos >= buffer.length) {
76
+ return pos;
77
+ }
78
+ const firstByte = buffer[pos];
79
+ if (firstByte === BYTE_QUOTE) {
80
+ return skipString(buffer, pos);
81
+ }
82
+ if (firstByte === BYTE_OPEN_BRACE || firstByte === BYTE_OPEN_BRACKET) {
83
+ const delimiterStack = [];
84
+ delimiterStack.push(firstByte === BYTE_OPEN_BRACE ? BYTE_CLOSE_BRACE : BYTE_CLOSE_BRACKET);
85
+ pos++;
86
+ while (pos < buffer.length) {
87
+ const byte = buffer[pos];
88
+ if (byte === BYTE_QUOTE) {
89
+ pos = skipString(buffer, pos);
90
+ continue;
91
+ }
92
+ if (byte === BYTE_OPEN_BRACE) {
93
+ delimiterStack.push(BYTE_CLOSE_BRACE);
94
+ }
95
+ else if (byte === BYTE_OPEN_BRACKET) {
96
+ delimiterStack.push(BYTE_CLOSE_BRACKET);
97
+ }
98
+ else if (byte === BYTE_CLOSE_BRACE || byte === BYTE_CLOSE_BRACKET) {
99
+ const expected = delimiterStack.pop();
100
+ if (expected !== byte) {
101
+ throw new SyntaxError('Unexpected delimiter in JSON');
102
+ }
103
+ if (delimiterStack.length === 0) {
104
+ pos++;
105
+ return pos;
106
+ }
107
+ }
108
+ pos++;
109
+ }
110
+ throw new SyntaxError('Unexpected end of JSON input');
111
+ }
112
+ const valStart = pos;
113
+ while (pos < buffer.length) {
114
+ const byte = buffer[pos];
115
+ if (byte === BYTE_COMMA ||
116
+ byte === BYTE_CLOSE_BRACE ||
117
+ byte === BYTE_CLOSE_BRACKET ||
118
+ byte === 0x20 ||
119
+ byte === 0x09 ||
120
+ byte === 0x0a ||
121
+ byte === 0x0d) {
122
+ break;
123
+ }
124
+ pos++;
125
+ }
126
+ if (pos === valStart) {
127
+ throw new SyntaxError('Expected JSON value');
128
+ }
129
+ return pos;
130
+ }
131
+ /**
132
+ * Scans trace events from a JSON array in bounded batches to limit memory consumption.
133
+ *
134
+ * @param buffer - The raw byte buffer containing the events array.
135
+ * @param startPos - The index immediately after the opening array bracket.
136
+ * @param config - Configuration settings controlling batch sizes and text decoding.
137
+ * @returns An object containing the parsed events and the ending buffer position.
138
+ * @throws {SyntaxError} If the event array contains malformed JSON, unbalanced delimiters, or unexpected tokens.
139
+ */
140
+ function parseEventsArray(buffer, startPos, config) {
141
+ const events = [];
142
+ let batchStart = -1;
143
+ let lastEventEnd = -1;
144
+ let batchEventCount = 0;
145
+ let depth = 0;
146
+ let i = startPos;
147
+ let closed = false;
148
+ let state = 'expect_element_or_end';
149
+ const flushBatch = () => {
150
+ if (batchStart !== -1 && lastEventEnd > batchStart) {
151
+ // Slicing between batchStart and lastEventEnd is safe for UTF-8 decoding.
152
+ // Both boundaries are ASCII structural braces ({ and }) that align with code unit boundaries.
153
+ const slice = buffer.subarray(batchStart, lastEventEnd);
154
+ const chunkText = config.decoder.decode(slice);
155
+ // Wrapping comma-delimited event objects in brackets creates a valid JSON array for the parser.
156
+ const parsed = JSON.parse(`[${chunkText}]`);
157
+ // Append items iteratively to avoid exceeding V8 call stack size limits on large batches.
158
+ for (const event of parsed) {
159
+ events.push(event);
160
+ }
161
+ batchStart = -1;
162
+ batchEventCount = 0;
163
+ }
164
+ };
165
+ while (i < buffer.length) {
166
+ const byte = buffer[i];
167
+ if (depth > 0) {
168
+ if (byte === BYTE_QUOTE) {
169
+ i = skipString(buffer, i);
170
+ continue;
171
+ }
172
+ if (byte === BYTE_OPEN_BRACE) {
173
+ depth++;
174
+ i++;
175
+ continue;
176
+ }
177
+ if (byte === BYTE_CLOSE_BRACE) {
178
+ depth--;
179
+ if (depth === 0) {
180
+ lastEventEnd = i + 1;
181
+ batchEventCount++;
182
+ state = 'expect_comma_or_end';
183
+ // Check thresholds after recording the completed event.
184
+ // Checking batchEventCount after incrementing ensures batches cap at exactly eventsPerBatch.
185
+ // Individual events are atomic JSON objects and cannot be split mid-event; when an event
186
+ // pushes currentBatchBytes over maxBatchBytes, the completed event is flushed immediately.
187
+ const currentBatchBytes = lastEventEnd - batchStart;
188
+ if (batchEventCount >= config.eventsPerBatch ||
189
+ currentBatchBytes >= config.maxBatchBytes) {
190
+ flushBatch();
191
+ }
192
+ }
193
+ i++;
194
+ continue;
195
+ }
196
+ i++;
197
+ continue;
198
+ }
199
+ // When depth is 0, scan top-level array delimiter and separator tokens.
200
+ if (byte === 0x20 || byte === 0x09 || byte === 0x0a || byte === 0x0d) {
201
+ i++;
202
+ continue;
203
+ }
204
+ if (byte === BYTE_OPEN_BRACE) {
205
+ if (state !== 'expect_element_or_end' && state !== 'expect_element') {
206
+ throw new SyntaxError('Expected "," or "]" in JSON array');
207
+ }
208
+ depth = 1;
209
+ if (batchStart === -1) {
210
+ batchStart = i;
211
+ }
212
+ i++;
213
+ continue;
214
+ }
215
+ if (byte === BYTE_COMMA) {
216
+ if (state !== 'expect_comma_or_end') {
217
+ throw new SyntaxError('Unexpected token "," in JSON array');
218
+ }
219
+ state = 'expect_element';
220
+ i++;
221
+ continue;
222
+ }
223
+ if (byte === BYTE_CLOSE_BRACKET) {
224
+ if (state === 'expect_element') {
225
+ throw new SyntaxError('Unexpected token "]" in JSON array');
226
+ }
227
+ closed = true;
228
+ i++;
229
+ break;
230
+ }
231
+ if (byte === BYTE_CLOSE_BRACE) {
232
+ throw new SyntaxError('Unexpected token "}" in JSON');
233
+ }
234
+ throw new SyntaxError('Unexpected token in JSON array');
235
+ }
236
+ if (!closed || depth !== 0) {
237
+ throw new SyntaxError('Unexpected end of JSON input');
238
+ }
239
+ flushBatch();
240
+ return { events, endPos: i };
241
+ }
242
+ /**
243
+ * Parses Chrome DevTools trace events and metadata from a raw byte buffer.
244
+ * Supports both root array format ([...]) and object container format ({"traceEvents": [...]}).
245
+ * Parses events in chunks to prevent V8 string length and memory exhaustion errors.
246
+ *
247
+ * @param buffer - The raw trace buffer to parse.
248
+ * @param options - Optional configuration settings for batch processing.
249
+ * @returns A {@link ParsedTraceBuffer} containing parsed trace events and optional file metadata, or an object with an empty events array if the buffer is empty or contains only whitespace.
250
+ * @throws {Error} If the buffer contains non-whitespace data that does not begin with a valid JSON array or object.
251
+ * @throws {SyntaxError} If the underlying JSON syntax within batches or metadata is invalid.
252
+ */
253
+ export function parseTraceEventsFromBuffer(buffer, options = {}) {
254
+ const eventsPerBatch = typeof options.eventsPerBatch === 'number' &&
255
+ Number.isFinite(options.eventsPerBatch) &&
256
+ options.eventsPerBatch > 0
257
+ ? options.eventsPerBatch
258
+ : DEFAULT_EVENTS_PER_BATCH;
259
+ const maxBatchBytes = typeof options.maxBatchBytes === 'number' &&
260
+ Number.isFinite(options.maxBatchBytes) &&
261
+ options.maxBatchBytes > 0
262
+ ? options.maxBatchBytes
263
+ : DEFAULT_MAX_BATCH_BYTES;
264
+ const decoder = new TextDecoder();
265
+ const config = {
266
+ eventsPerBatch,
267
+ maxBatchBytes,
268
+ decoder,
269
+ };
270
+ let pos = skipWhitespace(buffer, 0);
271
+ if (pos >= buffer.length) {
272
+ return { events: [] };
273
+ }
274
+ const firstByte = buffer[pos];
275
+ if (firstByte === BYTE_OPEN_BRACKET) {
276
+ const { events, endPos } = parseEventsArray(buffer, pos + 1, config);
277
+ const trailingPos = skipWhitespace(buffer, endPos);
278
+ if (trailingPos < buffer.length) {
279
+ throw new SyntaxError('Unexpected non-whitespace character after JSON');
280
+ }
281
+ return { events };
282
+ }
283
+ if (firstByte === BYTE_OPEN_BRACE) {
284
+ pos++;
285
+ let events = [];
286
+ let metadata;
287
+ let closed = false;
288
+ let expectComma = false;
289
+ while (pos < buffer.length) {
290
+ pos = skipWhitespace(buffer, pos);
291
+ if (pos >= buffer.length) {
292
+ break;
293
+ }
294
+ if (buffer[pos] === BYTE_CLOSE_BRACE) {
295
+ closed = true;
296
+ pos++;
297
+ break;
298
+ }
299
+ if (expectComma) {
300
+ if (buffer[pos] !== BYTE_COMMA) {
301
+ throw new SyntaxError('Expected "," or "}" after property value in JSON');
302
+ }
303
+ pos++;
304
+ pos = skipWhitespace(buffer, pos);
305
+ }
306
+ if (pos >= buffer.length) {
307
+ break;
308
+ }
309
+ if (buffer[pos] !== BYTE_QUOTE) {
310
+ throw new SyntaxError('Expected property name or "}" in JSON');
311
+ }
312
+ const keyStart = pos;
313
+ pos = skipString(buffer, pos);
314
+ const keyJson = decoder.decode(buffer.subarray(keyStart, pos));
315
+ const parsedKey = JSON.parse(keyJson);
316
+ if (typeof parsedKey !== 'string') {
317
+ throw new SyntaxError('Expected property name in JSON');
318
+ }
319
+ const key = parsedKey;
320
+ pos = skipWhitespace(buffer, pos);
321
+ if (pos >= buffer.length || buffer[pos] !== BYTE_COLON) {
322
+ throw new SyntaxError('Expected ":" after property name in JSON');
323
+ }
324
+ pos++;
325
+ pos = skipWhitespace(buffer, pos);
326
+ if (key === 'traceEvents') {
327
+ if (pos >= buffer.length || buffer[pos] !== BYTE_OPEN_BRACKET) {
328
+ throw new SyntaxError('Expected "[" for "traceEvents" in JSON');
329
+ }
330
+ const arrayResult = parseEventsArray(buffer, pos + 1, config);
331
+ events = arrayResult.events;
332
+ pos = arrayResult.endPos;
333
+ }
334
+ else if (key === 'metadata') {
335
+ if (pos >= buffer.length || buffer[pos] !== BYTE_OPEN_BRACE) {
336
+ throw new SyntaxError('Expected "{" for "metadata" in JSON');
337
+ }
338
+ const metaStart = pos;
339
+ pos = skipValue(buffer, pos);
340
+ const metaSlice = buffer.subarray(metaStart, pos);
341
+ const metaText = decoder.decode(metaSlice);
342
+ const parsedMetadata = JSON.parse(metaText);
343
+ metadata = parsedMetadata;
344
+ }
345
+ else {
346
+ pos = skipValue(buffer, pos);
347
+ }
348
+ expectComma = true;
349
+ }
350
+ if (!closed) {
351
+ throw new SyntaxError('Unexpected end of JSON input');
352
+ }
353
+ const trailingPos = skipWhitespace(buffer, pos);
354
+ if (trailingPos < buffer.length) {
355
+ throw new SyntaxError('Unexpected non-whitespace character after JSON');
356
+ }
357
+ return { events, metadata };
358
+ }
359
+ throw new Error('Invalid trace buffer: expected JSON object or array.');
360
+ }
361
+ //# sourceMappingURL=ChunkedTraceParser.js.map
@@ -0,0 +1,270 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import fsSync from 'node:fs';
7
+ import path from 'node:path';
8
+ import { DevTools } from '../third_party/index.js';
9
+ import { createIdGenerator, stableIdSymbol, } from '../utils/id.js';
10
+ const VALID_EXTENSIONS = ['.heapsnapshot', '.heaptimeline'];
11
+ function hasValidHeapSnapshotExtension(filePath) {
12
+ return VALID_EXTENSIONS.some(ext => filePath.endsWith(ext));
13
+ }
14
+ export class HeapSnapshotManager {
15
+ #snapshotIdGenerator = createIdGenerator();
16
+ #snapshots = new Map();
17
+ async getSnapshot(filePath) {
18
+ if (!hasValidHeapSnapshotExtension(filePath)) {
19
+ throw new Error(`File ${filePath} must have a .heapsnapshot or .heaptimeline extension.`);
20
+ }
21
+ const absolutePath = path.resolve(filePath);
22
+ const cached = this.#snapshots.get(absolutePath);
23
+ if (cached) {
24
+ return cached.snapshot;
25
+ }
26
+ const uid = this.#snapshotIdGenerator();
27
+ const { snapshot, worker } = await this.#loadSnapshot(absolutePath, uid);
28
+ this.#snapshots.set(absolutePath, {
29
+ snapshot,
30
+ worker,
31
+ idToClassKey: [''],
32
+ classKeyToId: new Map(),
33
+ });
34
+ return snapshot;
35
+ }
36
+ async #applyNodeFilter(snapshot, filter, filterName, objectId) {
37
+ if (filterName === 'attributedToSpecificNativeContext') {
38
+ if (objectId === undefined) {
39
+ throw new Error('objectId is required when filterName is attributedToSpecificNativeContext');
40
+ }
41
+ const nodeIndex = await snapshot.nodeIndexForId(objectId);
42
+ if (nodeIndex === undefined) {
43
+ throw new Error(`Node with ID ${objectId} not found`);
44
+ }
45
+ filter.filterName = `nativeContext_${nodeIndex}`;
46
+ }
47
+ else if (filterName) {
48
+ filter.filterName = filterName;
49
+ }
50
+ }
51
+ async getAggregates(filePath, filterName, objectId) {
52
+ const snapshot = await this.getSnapshot(filePath);
53
+ const filter = new DevTools.HeapSnapshotModel.HeapSnapshotModel.NodeFilter();
54
+ await this.#applyNodeFilter(snapshot, filter, filterName, objectId);
55
+ const aggregates = await snapshot.aggregatesWithFilter(filter);
56
+ let objectCount = 0;
57
+ let totalSelfSize = 0;
58
+ for (const [key, aggregate] of Object.entries(aggregates)) {
59
+ const id = await this.getOrCreateIdForClassKey(filePath, key);
60
+ aggregate[stableIdSymbol] = id;
61
+ objectCount += aggregate.count;
62
+ totalSelfSize += aggregate.self;
63
+ }
64
+ return {
65
+ aggregates,
66
+ objectCount,
67
+ totalSelfSize,
68
+ };
69
+ }
70
+ async getStats(filePath) {
71
+ const snapshot = await this.getSnapshot(filePath);
72
+ return await snapshot.getStatistics();
73
+ }
74
+ async getStaticData(filePath) {
75
+ const snapshot = await this.getSnapshot(filePath);
76
+ return snapshot.staticData;
77
+ }
78
+ async getNativeContextSizes(filePath) {
79
+ const snapshot = await this.getSnapshot(filePath);
80
+ return await snapshot.getNativeContextSizes();
81
+ }
82
+ async getRetainedByContextSummary(filePath) {
83
+ const snapshot = await this.getSnapshot(filePath);
84
+ return await snapshot.getRetainedByContextSummary();
85
+ }
86
+ async getOrCreateIdForClassKey(filePath, classKey) {
87
+ const cached = this.#getCachedSnapshot(filePath);
88
+ let id = cached.classKeyToId.get(classKey);
89
+ if (!id) {
90
+ id = cached.idToClassKey.length;
91
+ cached.classKeyToId.set(classKey, id);
92
+ cached.idToClassKey.push(classKey);
93
+ }
94
+ return id;
95
+ }
96
+ async getNodesById(filePath, id, filterName, objectId) {
97
+ const snapshot = await this.getSnapshot(filePath);
98
+ const filter = new DevTools.HeapSnapshotModel.HeapSnapshotModel.NodeFilter();
99
+ await this.#applyNodeFilter(snapshot, filter, filterName, objectId);
100
+ const className = await this.resolveClassKeyFromId(filePath, id);
101
+ if (!className) {
102
+ throw new Error(`Class with ID ${id} not found in heap snapshot`);
103
+ }
104
+ const provider = snapshot.createNodesProviderForClass(className, filter);
105
+ return await provider.serializeItemsRange(0, Infinity);
106
+ }
107
+ async getRetainers(filePath, nodeId) {
108
+ const snapshot = await this.getSnapshot(filePath);
109
+ const nodeIndex = await snapshot.nodeIndexForId(nodeId);
110
+ if (nodeIndex === undefined) {
111
+ throw new Error(`Node with ID ${nodeId} not found`);
112
+ }
113
+ const provider = snapshot.createRetainingEdgesProvider(nodeIndex);
114
+ return await provider.serializeItemsRange(0, Infinity);
115
+ }
116
+ async getObjectInfo(filePath, nodeId) {
117
+ const snapshot = await this.getSnapshot(filePath);
118
+ const nodeIndex = await snapshot.nodeIndexForId(nodeId);
119
+ if (nodeIndex === undefined) {
120
+ throw new Error(`Node with ID ${nodeId} not found`);
121
+ }
122
+ return await snapshot.getObjectInfo(nodeIndex);
123
+ }
124
+ async getRetainingPaths(filePath, nodeId, maxDepth, maxNodes, maxSiblings) {
125
+ const snapshot = await this.getSnapshot(filePath);
126
+ const nodeIndex = await snapshot.nodeIndexForId(nodeId);
127
+ if (nodeIndex === undefined) {
128
+ throw new Error(`Node with ID ${nodeId} not found`);
129
+ }
130
+ return await snapshot.getRetainingPaths(nodeIndex, maxDepth, maxNodes, maxSiblings);
131
+ }
132
+ async getDominatorsOf(filePath, nodeId) {
133
+ const snapshot = await this.getSnapshot(filePath);
134
+ const nodeIndex = await snapshot.nodeIndexForId(nodeId);
135
+ if (nodeIndex === undefined) {
136
+ throw new Error(`Node with ID ${nodeId} not found`);
137
+ }
138
+ return await snapshot.getDominatorsOf(nodeIndex);
139
+ }
140
+ async getEdges(filePath, nodeId, options) {
141
+ const snapshot = await this.getSnapshot(filePath);
142
+ const nodeIndex = await snapshot.nodeIndexForId(nodeId);
143
+ if (nodeIndex === undefined) {
144
+ throw new Error(`Node with ID ${nodeId} not found`);
145
+ }
146
+ const provider = snapshot.createEdgesProvider(nodeIndex, options);
147
+ return await provider.serializeItemsRange(0, Infinity);
148
+ }
149
+ async getClassDiffs(baseFilePath, currentFilePath) {
150
+ const rawDiffs = await this.#getSortedRawClassDiffs(baseFilePath, currentFilePath);
151
+ return rawDiffs.map(rawDiff => ({
152
+ className: rawDiff.name,
153
+ addedCount: rawDiff.addedCount,
154
+ removedCount: rawDiff.removedCount,
155
+ countDelta: rawDiff.countDelta,
156
+ addedSize: rawDiff.addedSize,
157
+ removedSize: rawDiff.removedSize,
158
+ sizeDelta: rawDiff.sizeDelta,
159
+ }));
160
+ }
161
+ async getDetailedClassDiff(baseFilePath, currentFilePath, classIndex) {
162
+ const classDiffs = await this.#getSortedRawClassDiffs(baseFilePath, currentFilePath);
163
+ const rawDiff = classDiffs[classIndex];
164
+ if (!rawDiff) {
165
+ throw new Error(`Invalid classIndex: ${classIndex}. Total classes with changes: ${classDiffs.length}`);
166
+ }
167
+ return {
168
+ className: rawDiff.name,
169
+ addedCount: rawDiff.addedCount,
170
+ removedCount: rawDiff.removedCount,
171
+ countDelta: rawDiff.countDelta,
172
+ addedSize: rawDiff.addedSize,
173
+ removedSize: rawDiff.removedSize,
174
+ sizeDelta: rawDiff.sizeDelta,
175
+ addedIds: rawDiff.addedIds ?? [],
176
+ addedSelfSizes: rawDiff.addedSelfSizes ?? [],
177
+ deletedIds: rawDiff.deletedIds ?? [],
178
+ deletedSelfSizes: rawDiff.deletedSelfSizes ?? [],
179
+ };
180
+ }
181
+ #getCachedSnapshot(filePath) {
182
+ const absolutePath = path.resolve(filePath);
183
+ const cached = this.#snapshots.get(absolutePath);
184
+ if (!cached) {
185
+ throw new Error(`Snapshot not loaded for ${filePath}`);
186
+ }
187
+ return cached;
188
+ }
189
+ async #getSortedRawClassDiffs(baseFilePath, currentFilePath) {
190
+ const baseSnapshot = await this.getSnapshot(baseFilePath);
191
+ const currentSnapshot = await this.getSnapshot(currentFilePath);
192
+ const interfaceDefinitions = await currentSnapshot.interfaceDefinitions();
193
+ const aggregatesForDiff = await baseSnapshot.aggregatesForDiff(interfaceDefinitions);
194
+ const baseSnapshotId = baseSnapshot.uid;
195
+ if (baseSnapshotId === undefined) {
196
+ throw new Error('Base snapshot UID is undefined');
197
+ }
198
+ // DevTools calculateSnapshotDiff uses the first parameter (baseSnapshotId)
199
+ // as a cache key. We pass the unique UID of the base snapshot.
200
+ const rawDiffs = await currentSnapshot.calculateSnapshotDiff(baseSnapshotId, aggregatesForDiff);
201
+ // Return a filtered and sorted array here to ensure that
202
+ // compare_heapsnapshot_summary and compare_heapsnapshot_details agree
203
+ // on indices.
204
+ return Object.values(rawDiffs)
205
+ .filter(diff => diff.addedCount > 0 || diff.removedCount > 0)
206
+ .sort((a, b) => b.sizeDelta - a.sizeDelta);
207
+ }
208
+ async resolveClassKeyFromId(filePath, id) {
209
+ const cached = this.#getCachedSnapshot(filePath);
210
+ return cached.idToClassKey[id];
211
+ }
212
+ async #loadSnapshot(absolutePath, uid) {
213
+ const workerProxy = new DevTools.HeapSnapshotModel.HeapSnapshotProxy.HeapSnapshotWorkerProxy(() => {
214
+ /* noop */
215
+ }, DevTools.Common.Console.Console.instance(), import.meta.resolve('../third_party/devtools-heap-snapshot-worker.js'));
216
+ try {
217
+ const { promise: snapshotPromise, resolve: resolveSnapshot } = Promise.withResolvers();
218
+ const loaderProxy = workerProxy.createLoader(uid, snapshotProxy => {
219
+ resolveSnapshot(snapshotProxy);
220
+ });
221
+ const fileStream = fsSync.createReadStream(absolutePath, {
222
+ encoding: 'utf-8',
223
+ highWaterMark: 1024 * 1024,
224
+ });
225
+ for await (const chunk of fileStream) {
226
+ await loaderProxy.write(chunk);
227
+ }
228
+ await loaderProxy.close();
229
+ const snapshot = await snapshotPromise;
230
+ return { snapshot, worker: workerProxy };
231
+ }
232
+ catch (error) {
233
+ // The worker is created before the read, and a failed load never reaches
234
+ // the #snapshots map, so dispose()/disposeAll() can never clean it up.
235
+ // Dispose it here to avoid leaking a worker on every failed load (e.g. a
236
+ // missing or invalid .heapsnapshot path).
237
+ workerProxy.dispose();
238
+ throw error;
239
+ }
240
+ }
241
+ async getDuplicateStrings(filePath) {
242
+ const snapshot = await this.getSnapshot(filePath);
243
+ return await snapshot.getDuplicateStrings();
244
+ }
245
+ async queryObjects(filePath, options) {
246
+ const snapshot = await this.getSnapshot(filePath);
247
+ const provider = snapshot.queryObjects(options);
248
+ return await provider.serializeItemsRange(0, Infinity);
249
+ }
250
+ hasSnapshots() {
251
+ return this.#snapshots.size > 0;
252
+ }
253
+ disposeSnapshot(filePath) {
254
+ const absolutePath = path.resolve(filePath);
255
+ const cached = this.#snapshots.get(absolutePath);
256
+ if (cached) {
257
+ cached.worker.dispose();
258
+ this.#snapshots.delete(absolutePath);
259
+ return true;
260
+ }
261
+ return false;
262
+ }
263
+ dispose() {
264
+ for (const cached of this.#snapshots.values()) {
265
+ cached.worker.dispose();
266
+ }
267
+ this.#snapshots.clear();
268
+ }
269
+ }
270
+ //# sourceMappingURL=HeapSnapshotManager.js.map