opera-devtools-mcp 0.2.4 → 0.3.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 (330) hide show
  1. package/README.md +104 -7
  2. package/build/src/McpContext.js +365 -365
  3. package/build/src/McpPage.js +475 -48
  4. package/build/src/McpResponse.js +462 -288
  5. package/build/src/SlimMcpResponse.js +1 -1
  6. package/build/src/TextSnapshot.js +101 -22
  7. package/build/src/ToolHandler.js +142 -20
  8. package/build/src/bin/check-latest-version.js +27 -1
  9. package/build/src/bin/chrome-devtools-cli-options.js +573 -10
  10. package/build/src/bin/chrome-devtools-mcp-cli-options.js +119 -32
  11. package/build/src/bin/chrome-devtools-mcp-main.js +50 -7
  12. package/build/src/bin/chrome-devtools-mcp.js +7 -4
  13. package/build/src/bin/chrome-devtools.js +57 -14
  14. package/build/src/bin/opera-devtools-cli-options.js +3 -829
  15. package/build/src/bin/opera-devtools-mcp-cli-options.js +3 -348
  16. package/build/src/bin/opera-devtools-mcp-main.js +3 -37
  17. package/build/src/bin/opera-devtools-mcp.js +4 -19
  18. package/build/src/bin/opera-devtools.js +4 -185
  19. package/build/src/browser.js +45 -5
  20. package/build/src/{PageCollector.js → collectors/PageCollector.js} +64 -133
  21. package/build/src/collectors/ServiceWorkerCollector.js +171 -0
  22. package/build/src/daemon/client.js +75 -17
  23. package/build/src/daemon/daemon.js +92 -30
  24. package/build/src/daemon/utils.js +24 -8
  25. package/build/src/{DevtoolsUtils.js → devtools/DevtoolsUtils.js} +94 -88
  26. package/build/src/devtools/McpHostBindingAdapter.js +165 -0
  27. package/build/src/{issue-descriptions.js → devtools/issueDescriptions.js} +8 -6
  28. package/build/src/formatters/ConsoleFormatter.js +44 -11
  29. package/build/src/formatters/HeapSnapshotFormatter.js +140 -9
  30. package/build/src/formatters/IssueFormatter.js +7 -7
  31. package/build/src/formatters/NetworkFormatter.js +10 -8
  32. package/build/src/index.js +101 -232
  33. package/build/src/opera/branding.js +34 -0
  34. package/build/src/opera/browserFlags.js +85 -0
  35. package/build/src/opera/browserLaunch.js +52 -0
  36. package/build/src/opera/policy.js +50 -0
  37. package/build/src/opera/serviceWorkerRetry.js +37 -0
  38. package/build/src/opera/toolHandlerHooks.js +39 -0
  39. package/build/src/{tools → opera/tools}/opera.js +9 -21
  40. package/build/src/processors/HeapSnapshotManager.js +258 -0
  41. package/build/src/{trace-processing/parse.js → processors/PerformanceTrace.js} +9 -9
  42. package/build/src/telemetry/ClearcutLogger.js +12 -119
  43. package/build/src/telemetry/WatchdogClient.js +5 -5
  44. package/build/src/telemetry/errors.js +1 -1
  45. package/build/src/telemetry/flagUtils.js +6 -6
  46. package/build/src/telemetry/{toolMetricsUtils.js → metricsRegistry.js} +4 -11
  47. package/build/src/telemetry/persistence.js +3 -3
  48. package/build/src/telemetry/transformation.js +184 -0
  49. package/build/src/telemetry/watchdog/ClearcutSender.js +11 -11
  50. package/build/src/telemetry/watchdog/main.js +6 -6
  51. package/build/src/third_party/THIRD_PARTY_NOTICES +232 -1061
  52. package/build/src/third_party/bundled-packages.json +6 -8
  53. package/build/src/third_party/devtools-formatter-worker.js +63 -22
  54. package/build/src/third_party/devtools-heap-snapshot-worker.js +809 -182
  55. package/build/src/third_party/index.js +69558 -74691
  56. package/build/src/third_party/issue-descriptions/CoepCorpNotSameOrigin.md +2 -2
  57. package/build/src/third_party/issue-descriptions/CoepCorpNotSameOriginAfterDefaultedToSameOriginByCoep.md +3 -3
  58. package/build/src/third_party/issue-descriptions/CoepCorpNotSameSite.md +2 -2
  59. package/build/src/third_party/issue-descriptions/CoepFrameResourceNeedsCoepHeader.md +1 -1
  60. package/build/src/third_party/issue-descriptions/CompatibilityModeQuirks.md +1 -1
  61. package/build/src/third_party/issue-descriptions/CookieAttributeValueExceedsMaxSize.md +2 -2
  62. package/build/src/third_party/issue-descriptions/LowTextContrast.md +1 -1
  63. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorRead.md +1 -1
  64. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorSet.md +1 -1
  65. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnRead.md +1 -1
  66. package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnSet.md +1 -1
  67. package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeRead.md +3 -3
  68. package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeSet.md +3 -3
  69. package/build/src/third_party/issue-descriptions/bounceTrackingMitigations.md +1 -1
  70. package/build/src/third_party/issue-descriptions/connectionAllowlistEmbeddingRequirementNotSatisfied.md +26 -0
  71. package/build/src/third_party/issue-descriptions/connectionAllowlistIFrameAttributeLoosensEmbeddingRequirement.md +19 -0
  72. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowConnectionAllowlistFrom.md +21 -0
  73. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowlistItemType.md +2 -2
  74. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidHeader.md +2 -2
  75. package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidUrlPattern.md +3 -3
  76. package/build/src/third_party/issue-descriptions/connectionAllowlistItemNotInnerList.md +2 -2
  77. package/build/src/third_party/issue-descriptions/connectionAllowlistMoreThanOneList.md +2 -2
  78. package/build/src/third_party/issue-descriptions/connectionAllowlistReportingEndpointNotToken.md +1 -1
  79. package/build/src/third_party/issue-descriptions/cookieCrossSiteRedirectDowngrade.md +3 -3
  80. package/build/src/third_party/issue-descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +1 -1
  81. package/build/src/third_party/issue-descriptions/cookieExcludePortMismatch.md +1 -1
  82. package/build/src/third_party/issue-descriptions/cookieExcludeSchemeMismatch.md +1 -1
  83. package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutSet.md +1 -1
  84. package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutRead.md +1 -1
  85. package/build/src/third_party/issue-descriptions/corsAllowCredentialsRequired.md +1 -1
  86. package/build/src/third_party/issue-descriptions/corsDisabledScheme.md +2 -2
  87. package/build/src/third_party/issue-descriptions/corsDisallowedByMode.md +2 -2
  88. package/build/src/third_party/issue-descriptions/corsHeaderDisallowedByPreflightResponse.md +1 -1
  89. package/build/src/third_party/issue-descriptions/corsInvalidHeaderValues.md +3 -3
  90. package/build/src/third_party/issue-descriptions/corsLocalNetworkAccessPermissionDenied.md +1 -1
  91. package/build/src/third_party/issue-descriptions/corsMethodDisallowedByPreflightResponse.md +1 -1
  92. package/build/src/third_party/issue-descriptions/corsNoCorsRedirectModeNotFollow.md +1 -1
  93. package/build/src/third_party/issue-descriptions/corsOriginMismatch.md +3 -3
  94. package/build/src/third_party/issue-descriptions/corsPreflightResponseInvalid.md +2 -2
  95. package/build/src/third_party/issue-descriptions/corsRedirectContainsCredentials.md +3 -3
  96. package/build/src/third_party/issue-descriptions/corsWildcardOriginNotAllowed.md +4 -3
  97. package/build/src/third_party/issue-descriptions/cspEvalViolation.md +4 -4
  98. package/build/src/third_party/issue-descriptions/cspInlineViolation.md +2 -2
  99. package/build/src/third_party/issue-descriptions/cspTrustedTypesPolicyViolation.md +2 -2
  100. package/build/src/third_party/issue-descriptions/cspTrustedTypesSinkViolation.md +4 -4
  101. package/build/src/third_party/issue-descriptions/cspURLViolation.md +4 -4
  102. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsEmptyList.md +1 -0
  103. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsHttpNotFound.md +1 -0
  104. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidContentType.md +1 -0
  105. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidResponse.md +1 -0
  106. package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsNoResponse.md +1 -0
  107. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
  108. package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
  109. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownHttpNotFound.md +1 -0
  110. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidContentType.md +1 -0
  111. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidResponse.md +1 -0
  112. package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownNoResponse.md +1 -0
  113. package/build/src/third_party/issue-descriptions/emailVerificationRequestInvalidEmail.md +1 -0
  114. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksHttpNotFound.md +1 -0
  115. package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksInvalidResponse.md +1 -0
  116. package/build/src/third_party/issue-descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
  117. package/build/src/third_party/issue-descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
  118. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
  119. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
  120. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
  121. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
  122. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
  123. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
  124. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidAudience.md +1 -0
  125. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidIssuedAt.md +1 -0
  126. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidNonce.md +1 -0
  127. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidSdHash.md +1 -0
  128. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidTyp.md +1 -0
  129. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingAud.md +1 -0
  130. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingCnf.md +1 -0
  131. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingIat.md +1 -0
  132. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingNonce.md +1 -0
  133. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingSdHash.md +1 -0
  134. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbSignatureFailed.md +1 -0
  135. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmail.md +1 -0
  136. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmailVerified.md +1 -0
  137. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidHolderKey.md +1 -0
  138. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuedAt.md +1 -0
  139. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuer.md +1 -0
  140. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtJwksMissingKeys.md +1 -0
  141. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingCnf.md +1 -0
  142. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingEmail.md +1 -0
  143. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIat.md +1 -0
  144. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIss.md +1 -0
  145. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtSignatureFailed.md +1 -0
  146. package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtUnsupportedHeaderAlg.md +1 -0
  147. package/build/src/third_party/issue-descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
  148. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
  149. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
  150. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
  151. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
  152. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
  153. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
  154. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
  155. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
  156. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
  157. package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
  158. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsHttpNotFound.md +1 -1
  159. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsInvalidResponse.md +1 -1
  160. package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsNoResponse.md +1 -1
  161. package/build/src/third_party/issue-descriptions/federatedAuthRequestApprovalDeclined.md +1 -1
  162. package/build/src/third_party/issue-descriptions/federatedAuthRequestCanceled.md +1 -1
  163. package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorFetchingSignin.md +1 -1
  164. package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorIdToken.md +1 -1
  165. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenHttpNotFound.md +1 -1
  166. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -1
  167. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -1
  168. package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -1
  169. package/build/src/third_party/issue-descriptions/federatedAuthRequestInvalidSigninResponse.md +1 -1
  170. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestHttpNotFound.md +1 -1
  171. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestInvalidResponse.md +1 -1
  172. package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestNoResponse.md +1 -1
  173. package/build/src/third_party/issue-descriptions/federatedAuthRequestTooManyRequests.md +1 -1
  174. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidAccountsResponse.md +1 -1
  175. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidConfigOrWellKnown.md +1 -1
  176. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoAccountSharingPermission.md +1 -1
  177. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoApiPermission.md +1 -1
  178. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoReturningUserFromFetchedAccounts.md +1 -1
  179. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotIframe.md +1 -1
  180. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotPotentiallyTrustworthy.md +1 -1
  181. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSameOrigin.md +1 -1
  182. package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSignedInWithIdp.md +1 -1
  183. package/build/src/third_party/issue-descriptions/fetchingPartitionedBlobURL.md +2 -2
  184. package/build/src/third_party/issue-descriptions/genericBackUINavigationWouldSkipAd.md +4 -0
  185. package/build/src/third_party/issue-descriptions/genericFormAriaLabelledByToNonExistingIdError.md +2 -2
  186. package/build/src/third_party/issue-descriptions/genericFormAutocompleteAttributeEmptyError.md +1 -1
  187. package/build/src/third_party/issue-descriptions/genericFormDuplicateIdForInputError.md +1 -1
  188. package/build/src/third_party/issue-descriptions/genericFormEmptyIdAndNameAttributesForInputError.md +2 -2
  189. package/build/src/third_party/issue-descriptions/genericFormInputAssignedAutocompleteValueToIdOrNameAttributeError.md +2 -2
  190. package/build/src/third_party/issue-descriptions/genericFormInputHasWrongButWellIntendedAutocompleteValueError.md +1 -1
  191. package/build/src/third_party/issue-descriptions/genericFormInputWithNoLabelError.md +1 -1
  192. package/build/src/third_party/issue-descriptions/genericFormLabelForMatchesNonExistingIdError.md +2 -2
  193. package/build/src/third_party/issue-descriptions/genericFormLabelForNameError.md +1 -1
  194. package/build/src/third_party/issue-descriptions/genericFormLabelHasNeitherForNorNestedInputError.md +1 -1
  195. package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +1 -1
  196. package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +1 -1
  197. package/build/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +1 -1
  198. package/build/src/third_party/issue-descriptions/genericNavigationEntryMarkedSkippable.md +2 -2
  199. package/build/src/third_party/issue-descriptions/heavyAd.md +1 -1
  200. package/build/src/third_party/issue-descriptions/lazyLoadImageZeroSize.md +7 -0
  201. package/build/src/third_party/issue-descriptions/navigatingPartitionedBlobURL.md +3 -3
  202. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabled.md +1 -1
  203. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluder.md +1 -1
  204. package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluderParent.md +1 -1
  205. package/build/src/third_party/issue-descriptions/permissionElementFencedFrameDisallowed.md +2 -2
  206. package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooLarge.md +2 -2
  207. package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooSmall.md +2 -2
  208. package/build/src/third_party/issue-descriptions/permissionElementInsetBoxShadowUnsupported.md +1 -1
  209. package/build/src/third_party/issue-descriptions/permissionElementInvalidDisplayStyle.md +2 -2
  210. package/build/src/third_party/issue-descriptions/permissionElementInvalidSizeValue.md +2 -2
  211. package/build/src/third_party/issue-descriptions/permissionElementInvalidType.md +2 -2
  212. package/build/src/third_party/issue-descriptions/permissionElementInvalidTypeActivation.md +2 -2
  213. package/build/src/third_party/issue-descriptions/permissionElementNonOpaqueColor.md +1 -1
  214. package/build/src/third_party/issue-descriptions/permissionElementPaddingBottomUnsupported.md +2 -2
  215. package/build/src/third_party/issue-descriptions/permissionElementPaddingRightUnsupported.md +2 -2
  216. package/build/src/third_party/issue-descriptions/permissionElementRequestInProgress.md +2 -2
  217. package/build/src/third_party/issue-descriptions/permissionElementSecurityChecksFailed.md +1 -1
  218. package/build/src/third_party/issue-descriptions/permissionElementTypeNotSupported.md +2 -2
  219. package/build/src/third_party/issue-descriptions/permissionElementUntrustedEvent.md +1 -1
  220. package/build/src/third_party/issue-descriptions/placeholderDescriptionForInvisibleIssues.md +1 -1
  221. package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedOptGroupChild.md +1 -1
  222. package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedSelectChild.md +1 -1
  223. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentAttributesSelectDescendant.md +1 -1
  224. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentLegendChild.md +1 -1
  225. package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentOptionChild.md +1 -1
  226. package/build/src/third_party/issue-descriptions/selectElementAccessibilityNonPhrasingContentOptionChild.md +1 -1
  227. package/build/src/third_party/issue-descriptions/selectivePermissionsIntervention.md +3 -3
  228. package/build/src/third_party/issue-descriptions/sharedArrayBuffer.md +1 -1
  229. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +1 -1
  230. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorMatchingDictionaryNotUsed.md +1 -1
  231. package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md +1 -1
  232. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorCossOriginNoCorsRequest.md +1 -1
  233. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorDisallowedBySettings.md +1 -1
  234. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorExpiredResponse.md +1 -1
  235. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorFeatureDisabled.md +2 -2
  236. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidStructuredHeader.md +1 -1
  237. package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNavigationRequest.md +2 -2
  238. package/build/src/third_party/issue-descriptions/sriInvalidSignatureHeader.md +4 -4
  239. package/build/src/third_party/issue-descriptions/sriInvalidSignatureInputHeader.md +4 -4
  240. package/build/src/third_party/issue-descriptions/sriMissingSignatureHeader.md +1 -1
  241. package/build/src/third_party/issue-descriptions/sriMissingSignatureInputHeader.md +2 -2
  242. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsIncorrectLength.md +2 -2
  243. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsNotByteSequence.md +4 -4
  244. package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsParameterized.md +4 -4
  245. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentName.md +1 -1
  246. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentType.md +2 -2
  247. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidDerivedComponentParameter.md +1 -1
  248. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidHeaderComponentParameter.md +1 -1
  249. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidParameter.md +2 -2
  250. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderKeyIdLength.md +5 -5
  251. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingLabel.md +3 -3
  252. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingRequiredParameters.md +2 -2
  253. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueMissingComponents.md +2 -2
  254. package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueNotInnerList.md +2 -2
  255. package/build/src/third_party/issue-descriptions/sriValidationFailedIntegrityMismatch.md +4 -4
  256. package/build/src/third_party/issue-descriptions/sriValidationFailedInvalidLength.md +3 -3
  257. package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureExpired.md +2 -2
  258. package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureMismatch.md +2 -2
  259. package/build/src/third_party/issue-descriptions/stylesheetLateImport.md +1 -1
  260. package/build/src/third_party/issue-descriptions/summaryElementAccessibilityInteractiveContentSummaryDescendant.md +1 -1
  261. package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestLength.md +2 -2
  262. package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestType.md +3 -3
  263. package/build/src/third_party/issue-descriptions/unencodedDigestMalformedDictionary.md +2 -2
  264. package/build/src/third_party/issue-descriptions/unencodedDigestUnknownAlgorithm.md +1 -1
  265. package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +3177 -6340
  266. package/build/src/tools/ToolDefinition.js +2 -2
  267. package/build/src/tools/categories.js +3 -0
  268. package/build/src/tools/console.js +13 -0
  269. package/build/src/tools/emulation.js +30 -3
  270. package/build/src/tools/extensions.js +8 -1
  271. package/build/src/tools/input.js +246 -128
  272. package/build/src/tools/lighthouse.js +14 -7
  273. package/build/src/tools/memory.js +289 -25
  274. package/build/src/tools/network.js +10 -7
  275. package/build/src/tools/pages.js +33 -92
  276. package/build/src/tools/performance.js +67 -52
  277. package/build/src/tools/pwa.js +128 -0
  278. package/build/src/tools/screencast.js +35 -12
  279. package/build/src/tools/screenshot.js +234 -75
  280. package/build/src/tools/script.js +130 -45
  281. package/build/src/tools/slim/tools.js +3 -0
  282. package/build/src/tools/snapshot.js +7 -4
  283. package/build/src/tools/thirdPartyDeveloper.js +19 -9
  284. package/build/src/tools/tools.js +3 -1
  285. package/build/src/tools/webmcp.js +3 -1
  286. package/build/src/utils/WaitForHelper.js +299 -0
  287. package/build/src/utils/check-for-updates.js +8 -2
  288. package/build/src/utils/files.js +42 -3
  289. package/build/src/utils/logger.js +51 -0
  290. package/build/src/utils/polyfill.js +11 -0
  291. package/build/src/utils/url.js +43 -0
  292. package/build/src/version.js +1 -1
  293. package/package.json +42 -33
  294. package/build/src/DevToolsConnectionAdapter.js +0 -70
  295. package/build/src/HeapSnapshotManager.js +0 -110
  296. package/build/src/Mutex.js +0 -38
  297. package/build/src/WaitForHelper.js +0 -195
  298. package/build/src/bin/cliDefinitions.js +0 -616
  299. package/build/src/logger.js +0 -37
  300. package/build/src/polyfill.js +0 -8
  301. package/build/src/telemetry/metricUtils.js +0 -15
  302. package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeRead.md +0 -8
  303. package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeSet.md +0 -8
  304. package/build/src/third_party/issue-descriptions/SameSiteExcludeNavigationContextDowngrade.md +0 -8
  305. package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeRead.md +0 -8
  306. package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeSet.md +0 -8
  307. package/build/src/third_party/issue-descriptions/SameSiteWarnStrictLaxDowngradeStrict.md +0 -8
  308. package/build/src/third_party/issue-descriptions/arInsecureContext.md +0 -7
  309. package/build/src/third_party/issue-descriptions/arInvalidInfoHeader.md +0 -5
  310. package/build/src/third_party/issue-descriptions/arInvalidRegisterOsSourceHeader.md +0 -5
  311. package/build/src/third_party/issue-descriptions/arInvalidRegisterOsTriggerHeader.md +0 -5
  312. package/build/src/third_party/issue-descriptions/arInvalidRegisterSourceHeader.md +0 -5
  313. package/build/src/third_party/issue-descriptions/arInvalidRegisterTriggerHeader.md +0 -5
  314. package/build/src/third_party/issue-descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +0 -5
  315. package/build/src/third_party/issue-descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +0 -6
  316. package/build/src/third_party/issue-descriptions/arNoRegisterOsSourceHeader.md +0 -5
  317. package/build/src/third_party/issue-descriptions/arNoRegisterOsTriggerHeader.md +0 -5
  318. package/build/src/third_party/issue-descriptions/arNoRegisterSourceHeader.md +0 -5
  319. package/build/src/third_party/issue-descriptions/arNoRegisterTriggerHeader.md +0 -5
  320. package/build/src/third_party/issue-descriptions/arNoWebOrOsSupport.md +0 -4
  321. package/build/src/third_party/issue-descriptions/arOsSourceIgnored.md +0 -18
  322. package/build/src/third_party/issue-descriptions/arOsTriggerIgnored.md +0 -19
  323. package/build/src/third_party/issue-descriptions/arPermissionPolicyDisabled.md +0 -8
  324. package/build/src/third_party/issue-descriptions/arSourceAndTriggerHeaders.md +0 -9
  325. package/build/src/third_party/issue-descriptions/arSourceIgnored.md +0 -13
  326. package/build/src/third_party/issue-descriptions/arTriggerIgnored.md +0 -12
  327. package/build/src/third_party/issue-descriptions/arUntrustworthyReportingOrigin.md +0 -10
  328. package/build/src/third_party/issue-descriptions/arWebAndOsHeaders.md +0 -11
  329. package/build/src/utils/string.js +0 -37
  330. package/build/src/utils/types.js +0 -7
@@ -3,10 +3,61 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { logger } from '../logger.js';
6
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
7
+ if (value !== null && value !== void 0) {
8
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
9
+ var dispose, inner;
10
+ if (async) {
11
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
12
+ dispose = value[Symbol.asyncDispose];
13
+ }
14
+ if (dispose === void 0) {
15
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
16
+ dispose = value[Symbol.dispose];
17
+ if (async) inner = dispose;
18
+ }
19
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
20
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
21
+ env.stack.push({ value: value, dispose: dispose, async: async });
22
+ }
23
+ else if (async) {
24
+ env.stack.push({ async: true });
25
+ }
26
+ return value;
27
+ };
28
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
29
+ return function (env) {
30
+ function fail(e) {
31
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
32
+ env.hasError = true;
33
+ }
34
+ var r, s = 0;
35
+ function next() {
36
+ while (r = env.stack.pop()) {
37
+ try {
38
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
39
+ if (r.dispose) {
40
+ var result = r.dispose.call(r.value);
41
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
42
+ }
43
+ else s |= 1;
44
+ }
45
+ catch (e) {
46
+ fail(e);
47
+ }
48
+ }
49
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
50
+ if (env.hasError) throw env.error;
51
+ }
52
+ return next();
53
+ };
54
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
55
+ var e = new Error(message);
56
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
57
+ });
7
58
  import { zod } from '../third_party/index.js';
8
59
  import { parseKey } from '../utils/keyboard.js';
9
- import { appendWaitForResult, } from '../WaitForHelper.js';
60
+ import { logger } from '../utils/logger.js';
10
61
  import { ToolCategory } from './categories.js';
11
62
  import { definePageTool } from './ToolDefinition.js';
12
63
  const dblClickSchema = zod
@@ -22,47 +73,47 @@ const submitKeySchema = zod
22
73
  .optional()
23
74
  .describe('Optional key to press after typing. E.g., "Enter", "Tab", "Escape"');
24
75
  function handleActionError(error, uid) {
25
- logger('failed to act using a locator', error);
76
+ logger?.('failed to act using a locator', error);
26
77
  throw new Error(`Failed to interact with the element with uid ${uid}. The element did not become interactive within the configured timeout.`, {
27
78
  cause: error,
28
79
  });
29
80
  }
30
81
  async function selectNativeSelectOption(handle) {
31
- const selectHandle = await handle.evaluateHandle(node => {
32
- if (!(node instanceof HTMLOptionElement)) {
33
- return null;
34
- }
35
- const select = node.closest('select');
36
- if (!select || select.multiple || select.disabled || node.disabled) {
37
- return null;
38
- }
39
- const parentElement = node.parentElement;
40
- if (parentElement instanceof HTMLOptGroupElement &&
41
- parentElement.disabled) {
42
- return null;
43
- }
44
- return select;
45
- });
82
+ const env_1 = { stack: [], error: void 0, hasError: false };
46
83
  try {
47
- const select = selectHandle.asElement();
84
+ const selectHandle = __addDisposableResource(env_1, await handle.evaluateHandle(node => {
85
+ if (!(node instanceof HTMLOptionElement)) {
86
+ return null;
87
+ }
88
+ const select = node.closest('select');
89
+ if (!select || select.multiple || select.disabled || node.disabled) {
90
+ return null;
91
+ }
92
+ const parentElement = node.parentElement;
93
+ if (parentElement instanceof HTMLOptGroupElement &&
94
+ parentElement.disabled) {
95
+ return null;
96
+ }
97
+ return select;
98
+ }), false);
99
+ const select = __addDisposableResource(env_1, selectHandle.asElement(), false);
48
100
  if (!select) {
49
101
  return false;
50
102
  }
51
- const valueHandle = await handle.getProperty('value');
52
- try {
53
- const value = await valueHandle.jsonValue();
54
- if (typeof value !== 'string') {
55
- return false;
56
- }
57
- await select.asLocator().fill(value);
58
- }
59
- finally {
60
- void valueHandle.dispose();
103
+ const valueHandle = __addDisposableResource(env_1, await handle.getProperty('value'), false);
104
+ const value = await valueHandle.jsonValue();
105
+ if (typeof value !== 'string') {
106
+ return false;
61
107
  }
108
+ await select.asLocator().fill(value);
62
109
  return true;
63
110
  }
111
+ catch (e_1) {
112
+ env_1.error = e_1;
113
+ env_1.hasError = true;
114
+ }
64
115
  finally {
65
- void selectHandle.dispose();
116
+ __disposeResources(env_1);
66
117
  }
67
118
  }
68
119
  export const click = definePageTool({
@@ -80,34 +131,42 @@ export const click = definePageTool({
80
131
  includeSnapshot: includeSnapshotSchema,
81
132
  },
82
133
  blockedByDialog: true,
134
+ verifyFilesSchema: {},
83
135
  handler: async (request, response) => {
84
- const uid = request.params.uid;
85
- const handle = await request.page.getElementByUid(uid);
86
- const aXNode = request.page.getAXNodeByUid(uid);
87
- const shouldSelectNativeOption = !request.params.dblClick && aXNode?.role === 'option';
136
+ const env_2 = { stack: [], error: void 0, hasError: false };
88
137
  try {
89
- const result = await request.page.waitForEventsAfterAction(async () => {
90
- if (shouldSelectNativeOption &&
91
- (await selectNativeSelectOption(handle))) {
92
- return;
93
- }
94
- await handle.asLocator().click({
95
- count: request.params.dblClick ? 2 : 1,
138
+ const uid = request.params.uid;
139
+ const handle = __addDisposableResource(env_2, await request.page.getElementByUid(uid), false);
140
+ const aXNode = request.page.getAXNodeByUid(uid);
141
+ const shouldSelectNativeOption = !request.params.dblClick && aXNode?.role === 'option';
142
+ try {
143
+ const result = await request.page.waitForEventsAfterAction(async () => {
144
+ if (shouldSelectNativeOption &&
145
+ (await selectNativeSelectOption(handle))) {
146
+ return;
147
+ }
148
+ await handle.asLocator().click({
149
+ count: request.params.dblClick ? 2 : 1,
150
+ });
96
151
  });
97
- });
98
- response.appendResponseLine(request.params.dblClick
99
- ? `Successfully double clicked on the element`
100
- : `Successfully clicked on the element`);
101
- appendWaitForResult(response, result);
102
- if (request.params.includeSnapshot) {
103
- response.includeSnapshot();
152
+ response.appendResponseLine(request.params.dblClick
153
+ ? `Successfully double clicked on the element`
154
+ : `Successfully clicked on the element`);
155
+ response.attachWaitForResult(result);
156
+ if (request.params.includeSnapshot) {
157
+ response.includeSnapshot();
158
+ }
159
+ }
160
+ catch (error) {
161
+ handleActionError(error, uid);
104
162
  }
105
163
  }
106
- catch (error) {
107
- handleActionError(error, uid);
164
+ catch (e_2) {
165
+ env_2.error = e_2;
166
+ env_2.hasError = true;
108
167
  }
109
168
  finally {
110
- void handle.dispose();
169
+ __disposeResources(env_2);
111
170
  }
112
171
  },
113
172
  });
@@ -126,17 +185,18 @@ export const clickAt = definePageTool({
126
185
  includeSnapshot: includeSnapshotSchema,
127
186
  },
128
187
  blockedByDialog: true,
188
+ verifyFilesSchema: {},
129
189
  handler: async (request, response) => {
130
190
  const page = request.page;
131
191
  const result = await page.waitForEventsAfterAction(async () => {
132
192
  await page.pptrPage.mouse.click(request.params.x, request.params.y, {
133
- clickCount: request.params.dblClick ? 2 : 1,
193
+ count: request.params.dblClick ? 2 : 1,
134
194
  });
135
195
  });
136
196
  response.appendResponseLine(request.params.dblClick
137
197
  ? `Successfully double clicked at the coordinates`
138
198
  : `Successfully clicked at the coordinates`);
139
- appendWaitForResult(response, result);
199
+ response.attachWaitForResult(result);
140
200
  if (request.params.includeSnapshot) {
141
201
  response.includeSnapshot();
142
202
  }
@@ -156,24 +216,32 @@ export const hover = definePageTool({
156
216
  includeSnapshot: includeSnapshotSchema,
157
217
  },
158
218
  blockedByDialog: true,
219
+ verifyFilesSchema: {},
159
220
  handler: async (request, response) => {
160
- const uid = request.params.uid;
161
- const handle = await request.page.getElementByUid(uid);
221
+ const env_3 = { stack: [], error: void 0, hasError: false };
162
222
  try {
163
- const result = await request.page.waitForEventsAfterAction(async () => {
164
- await handle.asLocator().hover();
165
- });
166
- response.appendResponseLine(`Successfully hovered over the element`);
167
- appendWaitForResult(response, result);
168
- if (request.params.includeSnapshot) {
169
- response.includeSnapshot();
223
+ const uid = request.params.uid;
224
+ const handle = __addDisposableResource(env_3, await request.page.getElementByUid(uid), false);
225
+ try {
226
+ const result = await request.page.waitForEventsAfterAction(async () => {
227
+ await handle.asLocator().hover();
228
+ });
229
+ response.appendResponseLine(`Successfully hovered over the element`);
230
+ response.attachWaitForResult(result);
231
+ if (request.params.includeSnapshot) {
232
+ response.includeSnapshot();
233
+ }
234
+ }
235
+ catch (error) {
236
+ handleActionError(error, uid);
170
237
  }
171
238
  }
172
- catch (error) {
173
- handleActionError(error, uid);
239
+ catch (e_3) {
240
+ env_3.error = e_3;
241
+ env_3.hasError = true;
174
242
  }
175
243
  finally {
176
- void handle.dispose();
244
+ __disposeResources(env_3);
177
245
  }
178
246
  },
179
247
  });
@@ -185,26 +253,36 @@ async function selectOption(handle, aXNode, value) {
185
253
  let optionFound = false;
186
254
  for (const child of aXNode.children) {
187
255
  if (child.role === 'option' && child.name === value && child.value) {
188
- optionFound = true;
189
- const childHandle = await child.elementHandle();
190
- if (childHandle) {
191
- try {
192
- const childValueHandle = await childHandle.getProperty('value');
256
+ const env_4 = { stack: [], error: void 0, hasError: false };
257
+ try {
258
+ optionFound = true;
259
+ const childHandle = __addDisposableResource(env_4, await child.elementHandle(), false);
260
+ if (childHandle) {
261
+ const env_5 = { stack: [], error: void 0, hasError: false };
193
262
  try {
263
+ const childValueHandle = __addDisposableResource(env_5, await childHandle.getProperty('value'), false);
194
264
  const childValue = await childValueHandle.jsonValue();
195
- if (childValue) {
196
- await handle.asLocator().fill(childValue.toString());
265
+ if (typeof childValue === 'string') {
266
+ await handle.asLocator().fill(childValue);
197
267
  }
268
+ break;
269
+ }
270
+ catch (e_4) {
271
+ env_5.error = e_4;
272
+ env_5.hasError = true;
198
273
  }
199
274
  finally {
200
- void childValueHandle.dispose();
275
+ __disposeResources(env_5);
201
276
  }
202
- break;
203
- }
204
- finally {
205
- void childHandle.dispose();
206
277
  }
207
278
  }
279
+ catch (e_5) {
280
+ env_4.error = e_5;
281
+ env_4.hasError = true;
282
+ }
283
+ finally {
284
+ __disposeResources(env_4);
285
+ }
208
286
  }
209
287
  }
210
288
  if (!optionFound) {
@@ -215,43 +293,50 @@ function hasOptionChildren(aXNode) {
215
293
  return aXNode.children.some(child => child.role === 'option');
216
294
  }
217
295
  async function fillFormElement(uid, value, context, page) {
218
- const handle = await page.getElementByUid(uid);
296
+ const env_6 = { stack: [], error: void 0, hasError: false };
219
297
  try {
220
- const aXNode = context.getAXNodeByUid(uid);
221
- // We assume that combobox needs to be handled as select if it has
222
- // role='combobox' and option children.
223
- if (aXNode && aXNode.role === 'combobox' && hasOptionChildren(aXNode)) {
224
- await selectOption(handle, aXNode, value);
225
- }
226
- else {
227
- const isToggle = await handle.evaluate(el => {
228
- if (el instanceof HTMLInputElement) {
229
- return el.type === 'checkbox' || el.type === 'radio';
230
- }
231
- const role = el.getAttribute('role');
232
- return role === 'checkbox' || role === 'radio' || role === 'switch';
233
- });
234
- if (isToggle) {
235
- if (['true', 'false'].includes(value)) {
236
- await handle.asLocator().fill(value === 'true');
298
+ const handle = __addDisposableResource(env_6, await page.getElementByUid(uid), false);
299
+ try {
300
+ const aXNode = page.getAXNodeByUid(uid);
301
+ // We assume that combobox needs to be handled as select if it has
302
+ // role='combobox' and option children.
303
+ if (aXNode && aXNode.role === 'combobox' && hasOptionChildren(aXNode)) {
304
+ await selectOption(handle, aXNode, value);
305
+ }
306
+ else {
307
+ const isToggle = await handle.evaluate(el => {
308
+ if (el instanceof HTMLInputElement) {
309
+ return el.type === 'checkbox' || el.type === 'radio';
310
+ }
311
+ const role = el.getAttribute('role');
312
+ return role === 'checkbox' || role === 'radio' || role === 'switch';
313
+ });
314
+ if (isToggle) {
315
+ if (['true', 'false'].includes(value)) {
316
+ await handle.asLocator().fill(value === 'true');
317
+ }
318
+ else {
319
+ throw new Error(`Checkboxes, radio boxes and toggles require "true" or "false" value, but ${value} was used`);
320
+ }
237
321
  }
238
322
  else {
239
- throw new Error(`Checkboxes, radio boxes and toggles require "true" or "false" value, but ${value} was used`);
323
+ // Increase timeout for longer input values.
324
+ const timeoutPerChar = 10; // ms
325
+ const fillTimeout = page.pptrPage.getDefaultTimeout() + value.length * timeoutPerChar;
326
+ await handle.asLocator().setTimeout(fillTimeout).fill(value);
240
327
  }
241
328
  }
242
- else {
243
- // Increase timeout for longer input values.
244
- const timeoutPerChar = 10; // ms
245
- const fillTimeout = page.pptrPage.getDefaultTimeout() + value.length * timeoutPerChar;
246
- await handle.asLocator().setTimeout(fillTimeout).fill(value);
247
- }
329
+ }
330
+ catch (error) {
331
+ handleActionError(error, uid);
248
332
  }
249
333
  }
250
- catch (error) {
251
- handleActionError(error, uid);
334
+ catch (e_6) {
335
+ env_6.error = e_6;
336
+ env_6.hasError = true;
252
337
  }
253
338
  finally {
254
- void handle.dispose();
339
+ __disposeResources(env_6);
255
340
  }
256
341
  }
257
342
  export const fill = definePageTool({
@@ -271,13 +356,14 @@ export const fill = definePageTool({
271
356
  includeSnapshot: includeSnapshotSchema,
272
357
  },
273
358
  blockedByDialog: true,
359
+ verifyFilesSchema: {},
274
360
  handler: async (request, response, context) => {
275
361
  const page = request.page;
276
362
  const result = await page.waitForEventsAfterAction(async () => {
277
363
  await fillFormElement(request.params.uid, request.params.value, context, page);
278
364
  });
279
365
  response.appendResponseLine(`Successfully filled out the element`);
280
- appendWaitForResult(response, result);
366
+ response.attachWaitForResult(result);
281
367
  if (request.params.includeSnapshot) {
282
368
  response.includeSnapshot();
283
369
  }
@@ -295,6 +381,7 @@ export const typeText = definePageTool({
295
381
  submitKey: submitKeySchema,
296
382
  },
297
383
  blockedByDialog: true,
384
+ verifyFilesSchema: {},
298
385
  handler: async (request, response) => {
299
386
  const page = request.page;
300
387
  const result = await page.waitForEventsAfterAction(async () => {
@@ -304,7 +391,7 @@ export const typeText = definePageTool({
304
391
  }
305
392
  });
306
393
  response.appendResponseLine(`Typed text "${request.params.text}${request.params.submitKey ? ` + ${request.params.submitKey}` : ''}"`);
307
- appendWaitForResult(response, result);
394
+ response.attachWaitForResult(result);
308
395
  },
309
396
  });
310
397
  export const drag = definePageTool({
@@ -320,24 +407,29 @@ export const drag = definePageTool({
320
407
  includeSnapshot: includeSnapshotSchema,
321
408
  },
322
409
  blockedByDialog: true,
410
+ verifyFilesSchema: {},
323
411
  handler: async (request, response) => {
324
- const fromHandle = await request.page.getElementByUid(request.params.from_uid);
325
- const toHandle = await request.page.getElementByUid(request.params.to_uid);
412
+ const env_7 = { stack: [], error: void 0, hasError: false };
326
413
  try {
414
+ const fromHandle = __addDisposableResource(env_7, await request.page.getElementByUid(request.params.from_uid), false);
415
+ const toHandle = __addDisposableResource(env_7, await request.page.getElementByUid(request.params.to_uid), false);
327
416
  const result = await request.page.waitForEventsAfterAction(async () => {
328
417
  await fromHandle.drag(toHandle);
329
418
  await new Promise(resolve => setTimeout(resolve, 50));
330
419
  await toHandle.drop(fromHandle);
331
420
  });
332
421
  response.appendResponseLine(`Successfully dragged an element`);
333
- appendWaitForResult(response, result);
422
+ response.attachWaitForResult(result);
334
423
  if (request.params.includeSnapshot) {
335
424
  response.includeSnapshot();
336
425
  }
337
426
  }
427
+ catch (e_7) {
428
+ env_7.error = e_7;
429
+ env_7.hasError = true;
430
+ }
338
431
  finally {
339
- void fromHandle.dispose();
340
- void toHandle.dispose();
432
+ __disposeResources(env_7);
341
433
  }
342
434
  },
343
435
  });
@@ -362,6 +454,7 @@ export const fillForm = definePageTool({
362
454
  includeSnapshot: includeSnapshotSchema,
363
455
  },
364
456
  blockedByDialog: true,
457
+ verifyFilesSchema: {},
365
458
  handler: async (request, response, context) => {
366
459
  const page = request.page;
367
460
  let lastResult = {};
@@ -371,7 +464,7 @@ export const fillForm = definePageTool({
371
464
  });
372
465
  }
373
466
  response.appendResponseLine(`Successfully filled out the form`);
374
- appendWaitForResult(response, lastResult);
467
+ response.attachWaitForResult(lastResult);
375
468
  if (request.params.includeSnapshot) {
376
469
  response.includeSnapshot();
377
470
  }
@@ -388,17 +481,28 @@ export const uploadFile = definePageTool({
388
481
  uid: zod
389
482
  .string()
390
483
  .describe('The uid of the file input element or an element that will open file chooser on the page from the page content snapshot'),
391
- filePath: zod.string().describe('The local path of the file to upload'),
484
+ filePaths: zod
485
+ .array(zod.string())
486
+ .min(1)
487
+ .describe('One or more files paths to upload. File paths have to be local to the browser instance (not the MCP).'),
392
488
  includeSnapshot: includeSnapshotSchema,
393
489
  },
394
490
  blockedByDialog: true,
395
- handler: async (request, response, context) => {
396
- const { uid, filePath } = request.params;
397
- context.validatePath(filePath);
398
- const handle = (await request.page.getElementByUid(uid));
491
+ // We do not validate file paths for remote browser instances
492
+ // because they are on the remote host and not accessed by the MCP server.
493
+ verifyFilesSchema: {
494
+ filePaths: {
495
+ local: true,
496
+ remote: false,
497
+ },
498
+ },
499
+ handler: async (request, response) => {
500
+ const env_8 = { stack: [], error: void 0, hasError: false };
399
501
  try {
502
+ const { uid, filePaths } = request.params;
503
+ const handle = __addDisposableResource(env_8, (await request.page.getElementByUid(uid)), false);
400
504
  try {
401
- await handle.uploadFile(filePath);
505
+ await handle.uploadFile(...filePaths);
402
506
  }
403
507
  catch {
404
508
  // Some sites use a proxy element to trigger file upload instead of
@@ -409,7 +513,7 @@ export const uploadFile = definePageTool({
409
513
  request.page.pptrPage.waitForFileChooser({ timeout: 3000 }),
410
514
  handle.asLocator().click(),
411
515
  ]);
412
- await fileChooser.accept([filePath]);
516
+ await fileChooser.accept(filePaths);
413
517
  }
414
518
  catch {
415
519
  throw new Error(`Failed to upload file. The element could not accept the file directly, and clicking it did not trigger a file chooser.`);
@@ -418,10 +522,14 @@ export const uploadFile = definePageTool({
418
522
  if (request.params.includeSnapshot) {
419
523
  response.includeSnapshot();
420
524
  }
421
- response.appendResponseLine(`File uploaded from ${filePath}.`);
525
+ response.appendResponseLine(`File uploaded from ${filePaths.join(', ')}.`);
526
+ }
527
+ catch (e_8) {
528
+ env_8.error = e_8;
529
+ env_8.hasError = true;
422
530
  }
423
531
  finally {
424
- void handle.dispose();
532
+ __disposeResources(env_8);
425
533
  }
426
534
  },
427
535
  });
@@ -439,21 +547,31 @@ export const pressKey = definePageTool({
439
547
  includeSnapshot: includeSnapshotSchema,
440
548
  },
441
549
  blockedByDialog: true,
550
+ verifyFilesSchema: {},
442
551
  handler: async (request, response) => {
443
552
  const page = request.page;
444
553
  const tokens = parseKey(request.params.key);
445
554
  const [key, ...modifiers] = tokens;
446
555
  const result = await page.waitForEventsAfterAction(async () => {
447
- for (const modifier of modifiers) {
448
- await page.pptrPage.keyboard.down(modifier);
556
+ const heldModifiers = [];
557
+ try {
558
+ for (const modifier of modifiers) {
559
+ await page.pptrPage.keyboard.down(modifier);
560
+ heldModifiers.push(modifier);
561
+ }
562
+ await page.pptrPage.keyboard.press(key);
449
563
  }
450
- await page.pptrPage.keyboard.press(key);
451
- for (const modifier of modifiers.toReversed()) {
452
- await page.pptrPage.keyboard.up(modifier);
564
+ finally {
565
+ // Release every modifier that was successfully pressed, even if a
566
+ // later key event throws. Otherwise a failed press leaves modifiers
567
+ // logically held down in the browser (see #2309).
568
+ for (const modifier of heldModifiers.toReversed()) {
569
+ await page.pptrPage.keyboard.up(modifier);
570
+ }
453
571
  }
454
572
  });
455
573
  response.appendResponseLine(`Successfully pressed key: ${request.params.key}`);
456
- appendWaitForResult(response, result);
574
+ response.attachWaitForResult(result);
457
575
  if (request.params.includeSnapshot) {
458
576
  response.includeSnapshot();
459
577
  }
@@ -30,6 +30,9 @@ export const lighthouseAudit = definePageTool({
30
30
  .describe('Directory for reports. If omitted, uses temporary files.'),
31
31
  },
32
32
  blockedByDialog: true,
33
+ verifyFilesSchema: {
34
+ outputDirPath: true,
35
+ },
33
36
  handler: async (request, response, context) => {
34
37
  const page = request.page;
35
38
  const categories = [
@@ -40,7 +43,6 @@ export const lighthouseAudit = definePageTool({
40
43
  ];
41
44
  const formats = ['json', 'html'];
42
45
  const { mode = 'navigation', device = 'desktop', outputDirPath, } = request.params;
43
- context.validatePath(outputDirPath);
44
46
  const flags = {
45
47
  onlyCategories: categories,
46
48
  output: formats,
@@ -84,23 +86,28 @@ export const lighthouseAudit = definePageTool({
84
86
  }
85
87
  }
86
88
  finally {
87
- await context.restoreEmulation(page);
89
+ await page.restoreEmulation();
88
90
  }
89
91
  const lhr = result.lhr;
90
92
  const reportPaths = [];
91
93
  const encoder = new TextEncoder();
92
- for (const format of formats) {
94
+ const savePromises = formats.map(async (format) => {
93
95
  const report = generateReport(lhr, format);
94
96
  const data = encoder.encode(report);
95
97
  if (outputDirPath) {
96
98
  const reportPath = path.join(outputDirPath, `report`);
97
99
  const { filename } = await context.saveFile(data, reportPath, `.${format}`);
98
- reportPaths.push(filename);
100
+ return filename;
99
101
  }
100
- else {
101
- const { filepath } = await context.saveTemporaryFile(data, `report.${format}`);
102
- reportPaths.push(filepath);
102
+ const { filepath } = await context.saveTemporaryFile(data, `report.${format}`);
103
+ return filepath;
104
+ });
105
+ const results = await Promise.allSettled(savePromises);
106
+ for (const res of results) {
107
+ if (res.status === 'rejected') {
108
+ throw res.reason;
103
109
  }
110
+ reportPaths.push(res.value);
104
111
  }
105
112
  const categoryScores = Object.values(lhr.categories).map(c => ({
106
113
  id: c.id,