opera-devtools-mcp 0.2.4 → 0.4.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 +108 -8
  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 +614 -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 +116 -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 +193 -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 +7 -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 -4
  293. package/package.json +43 -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
@@ -5,6 +5,7 @@
5
5
  *
6
6
  * Modified by Opera Software AS.
7
7
  */
8
+ import * as operaTools from '../opera/tools/opera.js';
8
9
  import * as consoleTools from './console.js';
9
10
  import * as emulationTools from './emulation.js';
10
11
  import * as extensionTools from './extensions.js';
@@ -12,9 +13,9 @@ import * as inputTools from './input.js';
12
13
  import * as lighthouseTools from './lighthouse.js';
13
14
  import * as memoryTools from './memory.js';
14
15
  import * as networkTools from './network.js';
15
- import * as operaTools from './opera.js';
16
16
  import * as pagesTools from './pages.js';
17
17
  import * as performanceTools from './performance.js';
18
+ import * as pwaTools from './pwa.js';
18
19
  import * as screencastTools from './screencast.js';
19
20
  import * as screenshotTools from './screenshot.js';
20
21
  import * as scriptTools from './script.js';
@@ -36,6 +37,7 @@ export const createTools = (args) => {
36
37
  ...Object.values(operaTools),
37
38
  ...Object.values(pagesTools),
38
39
  ...Object.values(performanceTools),
40
+ ...Object.values(pwaTools),
39
41
  ...Object.values(screencastTools),
40
42
  ...Object.values(screenshotTools),
41
43
  ...Object.values(scriptTools),
@@ -15,7 +15,8 @@ export const listWebMcpTools = definePageTool({
15
15
  },
16
16
  schema: {},
17
17
  blockedByDialog: false,
18
- handler: async (_request, response, _context) => {
18
+ verifyFilesSchema: {},
19
+ handler: async (_request, response) => {
19
20
  response.setListWebMcpTools();
20
21
  },
21
22
  });
@@ -34,6 +35,7 @@ export const executeWebMcpTool = definePageTool({
34
35
  .describe('The JSON-stringified parameters to pass to the WebMCP tool'),
35
36
  },
36
37
  blockedByDialog: false,
38
+ verifyFilesSchema: {},
37
39
  handler: async (request, response) => {
38
40
  const toolName = request.params.toolName;
39
41
  let input = {};
@@ -0,0 +1,299 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
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
+ });
58
+ import { logger } from './logger.js';
59
+ export class WaitForHelper {
60
+ #abortController = new AbortController();
61
+ #page;
62
+ #stableDomTimeout;
63
+ #stableDomFor;
64
+ #expectNavigationIn;
65
+ #navigationTimeout;
66
+ #dialogHandled = false;
67
+ /** Track all dialogs as they pause the renderer. */
68
+ #dialogDetected = false;
69
+ #initialUrl;
70
+ constructor(page, cpuTimeoutMultiplier, networkTimeoutMultiplier) {
71
+ this.#stableDomTimeout = 3000 * cpuTimeoutMultiplier;
72
+ this.#stableDomFor = 100 * cpuTimeoutMultiplier;
73
+ this.#expectNavigationIn = 100 * cpuTimeoutMultiplier;
74
+ this.#navigationTimeout = 3000 * networkTimeoutMultiplier;
75
+ this.#page = page;
76
+ this.#initialUrl = page.url();
77
+ }
78
+ /**
79
+ * A wrapper that executes a action and waits for
80
+ * a potential navigation, after which it waits
81
+ * for the DOM to be stable before returning.
82
+ */
83
+ async waitForStableDom() {
84
+ const env_1 = { stack: [], error: void 0, hasError: false };
85
+ try {
86
+ // Bound the setup evaluation against the stable-DOM timeout. Without this
87
+ // cap a paused renderer (e.g. an open dialog) would make evaluateHandle
88
+ // hang until protocolTimeout (default 180s) while the tool mutex is held.
89
+ const stableDomObserver = __addDisposableResource(env_1, await Promise.race([
90
+ this.#page.evaluateHandle(timeout => {
91
+ let timeoutId;
92
+ function callback() {
93
+ clearTimeout(timeoutId);
94
+ timeoutId = setTimeout(() => {
95
+ domObserver.resolver.resolve();
96
+ domObserver.observer.disconnect();
97
+ }, timeout);
98
+ }
99
+ const domObserver = {
100
+ resolver: Promise.withResolvers(),
101
+ observer: new MutationObserver(callback),
102
+ };
103
+ // It's possible that the DOM is not gonna change so we
104
+ // need to start the timeout initially.
105
+ callback();
106
+ domObserver.observer.observe(document.body, {
107
+ childList: true,
108
+ subtree: true,
109
+ attributes: true,
110
+ });
111
+ return domObserver;
112
+ }, this.#stableDomFor),
113
+ this.timeout(this.#stableDomTimeout),
114
+ ]).catch(() => undefined), false);
115
+ if (!stableDomObserver) {
116
+ return;
117
+ }
118
+ this.#abortController.signal.addEventListener('abort', async () => {
119
+ try {
120
+ await stableDomObserver.evaluate(observer => {
121
+ observer.observer.disconnect();
122
+ observer.resolver.resolve();
123
+ });
124
+ }
125
+ catch {
126
+ // Ignored cleanup errors
127
+ }
128
+ });
129
+ return Promise.race([
130
+ stableDomObserver.evaluate(async (observer) => {
131
+ return await observer.resolver.promise;
132
+ }),
133
+ this.timeout(this.#stableDomTimeout).then(() => {
134
+ throw new Error('Timeout');
135
+ }),
136
+ ]);
137
+ }
138
+ catch (e_1) {
139
+ env_1.error = e_1;
140
+ env_1.hasError = true;
141
+ }
142
+ finally {
143
+ __disposeResources(env_1);
144
+ }
145
+ }
146
+ timeout(time) {
147
+ return new Promise(res => {
148
+ const id = setTimeout(res, time);
149
+ this.#abortController.signal.addEventListener('abort', () => {
150
+ res();
151
+ clearTimeout(id);
152
+ });
153
+ });
154
+ }
155
+ async waitForEventsAfterAction(action, options) {
156
+ if (this.#abortController.signal.aborted) {
157
+ throw new Error("Can't re-use a WaitForHelper");
158
+ }
159
+ const dialogHandler = (dialog) => {
160
+ this.#dialogDetected = true;
161
+ if (!options?.handleDialog) {
162
+ return;
163
+ }
164
+ let actionToTake;
165
+ if (typeof options.handleDialog === 'object') {
166
+ actionToTake = options.handleDialog[dialog.type()];
167
+ }
168
+ else {
169
+ actionToTake = options.handleDialog;
170
+ }
171
+ if (actionToTake) {
172
+ this.#dialogHandled = true;
173
+ if (actionToTake === 'dismiss') {
174
+ void dialog.dismiss();
175
+ }
176
+ else if (actionToTake === 'accept') {
177
+ void dialog.accept();
178
+ }
179
+ else {
180
+ void dialog.accept(actionToTake);
181
+ }
182
+ }
183
+ };
184
+ this.#page.on('dialog', dialogHandler);
185
+ this.#abortController.signal.addEventListener('abort', () => {
186
+ this.#page.off('dialog', dialogHandler);
187
+ });
188
+ // A scoped AbortController used to clean up navigation probe listeners.
189
+ // When aborted (either after navigation detection finishes or if this.#abortController
190
+ // aborts), it removes the CDP Page.frameStartedNavigating listener and automatically
191
+ // detaches the abort listener from this.#abortController.signal.
192
+ const navigationAbortController = new AbortController();
193
+ const navigationStartedResolvers = Promise.withResolvers();
194
+ const navigationListener = (event) => {
195
+ if (event.frameId !== this.#page.mainFrame()._id) {
196
+ return;
197
+ }
198
+ if (event.navigationType === 'sameDocument' ||
199
+ event.navigationType === 'historySameDocument') {
200
+ return;
201
+ }
202
+ navigationStartedResolvers.resolve(true);
203
+ };
204
+ this.#page._client().on('Page.frameStartedNavigating', navigationListener);
205
+ navigationAbortController.signal.addEventListener('abort', () => {
206
+ this.#page
207
+ ._client()
208
+ .off('Page.frameStartedNavigating', navigationListener);
209
+ });
210
+ this.#abortController.signal.addEventListener('abort', () => {
211
+ navigationStartedResolvers.resolve(false);
212
+ navigationAbortController.abort();
213
+ }, { signal: navigationAbortController.signal });
214
+ // Puppeteer's waitForNavigation must be started before the action runs so that
215
+ // it captures the pre-action loader ID. If started after the action triggers navigation,
216
+ // it risks recording the new loader ID and hanging until timeout.
217
+ // If no navigation occurs, this.#abortController will cancel it in the finally block.
218
+ const navigationFinished = this.#page
219
+ .waitForNavigation({
220
+ timeout: options?.timeout ?? this.#navigationTimeout,
221
+ signal: this.#abortController.signal,
222
+ ignoreSameDocumentNavigation: true,
223
+ })
224
+ .then(result => {
225
+ navigationStartedResolvers.resolve(true);
226
+ return result;
227
+ })
228
+ .catch(error => {
229
+ if (this.#abortController.signal.aborted ||
230
+ (error instanceof Error && error.name === 'AbortError')) {
231
+ return;
232
+ }
233
+ logger?.(error);
234
+ });
235
+ try {
236
+ await action();
237
+ }
238
+ catch (error) {
239
+ // Clear up pending promises
240
+ this.#abortController.abort();
241
+ throw error;
242
+ }
243
+ const expectNavigationIn = options?.expectNavigationIn ?? this.#expectNavigationIn;
244
+ const navigationStarted = await Promise.race([
245
+ navigationStartedResolvers.promise,
246
+ this.timeout(expectNavigationIn).then(() => {
247
+ navigationStartedResolvers.resolve(false);
248
+ return false;
249
+ }),
250
+ ]);
251
+ navigationAbortController.abort();
252
+ try {
253
+ // Only await navigation if one was actually initiated; otherwise, the
254
+ // pending waitForNavigation promise will be cancelled when this.#abortController aborts.
255
+ if (navigationStarted) {
256
+ await navigationFinished;
257
+ }
258
+ if (this.#dialogDetected) {
259
+ return this.#getResult();
260
+ }
261
+ // Wait for stable dom after navigation so we execute in
262
+ // the correct context
263
+ if (options?.waitForStableDom !== false) {
264
+ await this.waitForStableDom();
265
+ }
266
+ }
267
+ catch (error) {
268
+ logger?.(error);
269
+ }
270
+ finally {
271
+ this.#abortController.abort();
272
+ }
273
+ return this.#getResult();
274
+ }
275
+ #getResult() {
276
+ const urlAfterAction = this.#page.url();
277
+ return {
278
+ ...(urlAfterAction !== this.#initialUrl
279
+ ? { navigatedToUrl: urlAfterAction }
280
+ : {}),
281
+ dialogHandled: this.#dialogHandled,
282
+ };
283
+ }
284
+ }
285
+ export function getNetworkMultiplierFromString(condition) {
286
+ const puppeteerCondition = condition;
287
+ switch (puppeteerCondition) {
288
+ case 'Fast 4G':
289
+ return 1;
290
+ case 'Slow 4G':
291
+ return 2.5;
292
+ case 'Fast 3G':
293
+ return 5;
294
+ case 'Slow 3G':
295
+ return 10;
296
+ }
297
+ return 1;
298
+ }
299
+ //# sourceMappingURL=WaitForHelper.js.map
@@ -10,6 +10,7 @@ import fs from 'node:fs/promises';
10
10
  import os from 'node:os';
11
11
  import path from 'node:path';
12
12
  import process from 'node:process';
13
+ import { CACHE_DIR_NAME, ENV_NO_UPDATE_CHECKS } from '../opera/branding.js';
13
14
  import { VERSION } from '../version.js';
14
15
  /**
15
16
  * Notifies the user if an update is available.
@@ -21,11 +22,11 @@ export function resetUpdateCheckFlagForTesting() {
21
22
  isChecking = false;
22
23
  }
23
24
  export async function checkForUpdates(message) {
24
- if (isChecking || process.env['OPERA_DEVTOOLS_NO_UPDATE_CHECKS']) {
25
+ if (isChecking || process.env[ENV_NO_UPDATE_CHECKS]) {
25
26
  return;
26
27
  }
27
28
  isChecking = true;
28
- const cachePath = path.join(os.homedir(), '.cache', 'opera-devtools-mcp', 'latest.json');
29
+ const cachePath = path.join(os.homedir(), '.cache', CACHE_DIR_NAME, 'latest.json');
29
30
  let cachedVersion;
30
31
  let stats;
31
32
  try {
@@ -36,6 +37,10 @@ export async function checkForUpdates(message) {
36
37
  catch {
37
38
  // Ignore errors reading cache.
38
39
  }
40
+ // NOTE: upstream uses `semver.lt(VERSION, cachedVersion)` here. The fork
41
+ // deliberately compares for inequality, which also reports an "update" when
42
+ // the installed version is *newer* than the cached snapshot (e.g. after a
43
+ // downgrade or when running a local pre-release build).
39
44
  if (cachedVersion && cachedVersion !== VERSION) {
40
45
  console.warn(`\nUpdate available: ${VERSION} -> ${cachedVersion}\n${message}\n`);
41
46
  }
@@ -65,6 +70,7 @@ export async function checkForUpdates(message) {
65
70
  const child = child_process.spawn(process.execPath, [scriptPath, cachePath], {
66
71
  detached: true,
67
72
  stdio: 'ignore',
73
+ windowsHide: true,
68
74
  });
69
75
  child.unref();
70
76
  }
@@ -11,8 +11,47 @@ export async function getTempFilePath(filename) {
11
11
  const filepath = path.join(dir, filename);
12
12
  return filepath;
13
13
  }
14
- export function ensureExtension(filepath, extension) {
15
- const ext = path.extname(filepath);
16
- return filepath.slice(0, filepath.length - ext.length) + extension;
14
+ export async function resolveCanonicalPath(filePath) {
15
+ const absolutePath = path.resolve(filePath);
16
+ try {
17
+ // Get the true canonical path, resolving all symlinks.
18
+ return await fs.realpath(absolutePath);
19
+ }
20
+ catch (err) {
21
+ if (err &&
22
+ typeof err === 'object' &&
23
+ 'code' in err &&
24
+ err.code === 'ENOENT') {
25
+ // Find the nearest existing ancestor directory on the filesystem.
26
+ let current = absolutePath;
27
+ const missingSegments = [];
28
+ while (true) {
29
+ const parent = path.dirname(current);
30
+ if (parent === current) {
31
+ // Reached root directory but still couldn't resolve anything.
32
+ throw err;
33
+ }
34
+ try {
35
+ const canonicalParent = await fs.realpath(parent);
36
+ return path.join(canonicalParent, path.basename(current), ...missingSegments);
37
+ }
38
+ catch (parentErr) {
39
+ if (parentErr &&
40
+ typeof parentErr === 'object' &&
41
+ 'code' in parentErr &&
42
+ parentErr.code === 'ENOENT') {
43
+ missingSegments.unshift(path.basename(current));
44
+ current = parent;
45
+ }
46
+ else {
47
+ throw parentErr;
48
+ }
49
+ }
50
+ }
51
+ }
52
+ else {
53
+ throw err;
54
+ }
55
+ }
17
56
  }
18
57
  //# sourceMappingURL=files.js.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import fs from 'node:fs';
7
+ import util from 'node:util';
8
+ const mcpDebugNamespace = 'mcp:log';
9
+ let logFileStream;
10
+ const _debugLog = util.debuglog(mcpDebugNamespace);
11
+ export function saveLogsToFile(fileName) {
12
+ const logFile = fs.createWriteStream(fileName, { flags: 'a+' });
13
+ logFile.on('error', function (error) {
14
+ console.error(`Error when opening/writing to log file: ${error.message}`);
15
+ logFile.end();
16
+ process.exit(1);
17
+ });
18
+ logFileStream = logFile;
19
+ return logFile;
20
+ }
21
+ export function flushLogs(logFile, timeoutMs = 2000) {
22
+ return new Promise((resolve, reject) => {
23
+ const timeout = setTimeout(reject, timeoutMs);
24
+ logFile.end(() => {
25
+ clearTimeout(timeout);
26
+ resolve();
27
+ });
28
+ });
29
+ }
30
+ export const logger = (...args) => {
31
+ if (logFileStream) {
32
+ logFileStream.write(`${new Date().toISOString()} ${mcpDebugNamespace} ${util.format(...args)}\n`);
33
+ }
34
+ else if (_debugLog.enabled) {
35
+ _debugLog('%s %s', new Date().toISOString(), util.format(...args));
36
+ }
37
+ };
38
+ export const puppeteerLogger = (prefix) => {
39
+ if (logFileStream) {
40
+ return (...args) => {
41
+ logFileStream.write(`${new Date().toISOString()} ${prefix} ${util.format(...args)}\n`);
42
+ };
43
+ }
44
+ const dbg = util.debuglog(prefix);
45
+ return dbg.enabled
46
+ ? (...args) => {
47
+ dbg('%s %s', new Date().toISOString(), util.format(...args));
48
+ }
49
+ : undefined;
50
+ };
51
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { DisposableStack, AsyncDisposableStack, SuppressedError, } from '../third_party/index.js';
7
+ globalThis.DisposableStack ??= DisposableStack;
8
+ globalThis.AsyncDisposableStack ??= AsyncDisposableStack;
9
+ // @ts-expect-error Type mismatch between puppeteer-core and node for SuppressedError.
10
+ globalThis.SuppressedError ??= SuppressedError;
11
+ //# sourceMappingURL=polyfill.js.map
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ const ALLOWED_PROTOCOLS = new Set(['http:', 'https:', 'ws:', 'wss:']);
7
+ const IPV4_LOOPBACK_REGEX = /^127(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)){3}$/;
8
+ /**
9
+ * Determines whether a given URL string points to a localhost / loopback address.
10
+ *
11
+ * @param url The URL string to test.
12
+ * @returns true if the URL is a valid network URL pointing to localhost or a loopback IP.
13
+ */
14
+ export function isLocalhost(url) {
15
+ if (!url || typeof url !== 'string' || url.trim() === '') {
16
+ return false;
17
+ }
18
+ let parsed;
19
+ try {
20
+ parsed = new URL(url);
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ if (!ALLOWED_PROTOCOLS.has(parsed.protocol)) {
26
+ return false;
27
+ }
28
+ const hostname = parsed.hostname.toLowerCase().replace(/\.$/, '');
29
+ // 1. Check localhost and RFC 6761 *.localhost subdomains
30
+ if (hostname === 'localhost' || hostname.endsWith('.localhost')) {
31
+ return true;
32
+ }
33
+ // 2. Check IPv6 loopback ([::1] as returned by URL.hostname, or ::1)
34
+ if (hostname === '[::1]' || hostname === '::1') {
35
+ return true;
36
+ }
37
+ // 3. Check IPv4 loopback (127.0.0.0/8)
38
+ if (IPV4_LOOPBACK_REGEX.test(hostname)) {
39
+ return true;
40
+ }
41
+ return false;
42
+ }
43
+ //# sourceMappingURL=url.js.map
@@ -5,8 +5,5 @@
5
5
  *
6
6
  * Modified by Opera Software AS.
7
7
  */
8
- // If moved update release-please config
9
- // x-release-please-start-version
10
- export const VERSION = '0.2.2';
11
- // x-release-please-end
8
+ export const VERSION = '0.4.0';
12
9
  //# sourceMappingURL=version.js.map