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.
- package/README.md +104 -7
- package/build/src/McpContext.js +365 -365
- package/build/src/McpPage.js +475 -48
- package/build/src/McpResponse.js +462 -288
- package/build/src/SlimMcpResponse.js +1 -1
- package/build/src/TextSnapshot.js +101 -22
- package/build/src/ToolHandler.js +142 -20
- package/build/src/bin/check-latest-version.js +27 -1
- package/build/src/bin/chrome-devtools-cli-options.js +573 -10
- package/build/src/bin/chrome-devtools-mcp-cli-options.js +119 -32
- package/build/src/bin/chrome-devtools-mcp-main.js +50 -7
- package/build/src/bin/chrome-devtools-mcp.js +7 -4
- package/build/src/bin/chrome-devtools.js +57 -14
- package/build/src/bin/opera-devtools-cli-options.js +3 -829
- package/build/src/bin/opera-devtools-mcp-cli-options.js +3 -348
- package/build/src/bin/opera-devtools-mcp-main.js +3 -37
- package/build/src/bin/opera-devtools-mcp.js +4 -19
- package/build/src/bin/opera-devtools.js +4 -185
- package/build/src/browser.js +45 -5
- package/build/src/{PageCollector.js → collectors/PageCollector.js} +64 -133
- package/build/src/collectors/ServiceWorkerCollector.js +171 -0
- package/build/src/daemon/client.js +75 -17
- package/build/src/daemon/daemon.js +92 -30
- package/build/src/daemon/utils.js +24 -8
- package/build/src/{DevtoolsUtils.js → devtools/DevtoolsUtils.js} +94 -88
- package/build/src/devtools/McpHostBindingAdapter.js +165 -0
- package/build/src/{issue-descriptions.js → devtools/issueDescriptions.js} +8 -6
- package/build/src/formatters/ConsoleFormatter.js +44 -11
- package/build/src/formatters/HeapSnapshotFormatter.js +140 -9
- package/build/src/formatters/IssueFormatter.js +7 -7
- package/build/src/formatters/NetworkFormatter.js +10 -8
- package/build/src/index.js +101 -232
- package/build/src/opera/branding.js +34 -0
- package/build/src/opera/browserFlags.js +85 -0
- package/build/src/opera/browserLaunch.js +52 -0
- package/build/src/opera/policy.js +50 -0
- package/build/src/opera/serviceWorkerRetry.js +37 -0
- package/build/src/opera/toolHandlerHooks.js +39 -0
- package/build/src/{tools → opera/tools}/opera.js +9 -21
- package/build/src/processors/HeapSnapshotManager.js +258 -0
- package/build/src/{trace-processing/parse.js → processors/PerformanceTrace.js} +9 -9
- package/build/src/telemetry/ClearcutLogger.js +12 -119
- package/build/src/telemetry/WatchdogClient.js +5 -5
- package/build/src/telemetry/errors.js +1 -1
- package/build/src/telemetry/flagUtils.js +6 -6
- package/build/src/telemetry/{toolMetricsUtils.js → metricsRegistry.js} +4 -11
- package/build/src/telemetry/persistence.js +3 -3
- package/build/src/telemetry/transformation.js +184 -0
- package/build/src/telemetry/watchdog/ClearcutSender.js +11 -11
- package/build/src/telemetry/watchdog/main.js +6 -6
- package/build/src/third_party/THIRD_PARTY_NOTICES +232 -1061
- package/build/src/third_party/bundled-packages.json +6 -8
- package/build/src/third_party/devtools-formatter-worker.js +63 -22
- package/build/src/third_party/devtools-heap-snapshot-worker.js +809 -182
- package/build/src/third_party/index.js +69558 -74691
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameOrigin.md +2 -2
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameOriginAfterDefaultedToSameOriginByCoep.md +3 -3
- package/build/src/third_party/issue-descriptions/CoepCorpNotSameSite.md +2 -2
- package/build/src/third_party/issue-descriptions/CoepFrameResourceNeedsCoepHeader.md +1 -1
- package/build/src/third_party/issue-descriptions/CompatibilityModeQuirks.md +1 -1
- package/build/src/third_party/issue-descriptions/CookieAttributeValueExceedsMaxSize.md +2 -2
- package/build/src/third_party/issue-descriptions/LowTextContrast.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorRead.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureErrorSet.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnRead.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteNoneInsecureWarnSet.md +1 -1
- package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeRead.md +3 -3
- package/build/src/third_party/issue-descriptions/SameSiteUnspecifiedLaxAllowUnsafeSet.md +3 -3
- package/build/src/third_party/issue-descriptions/bounceTrackingMitigations.md +1 -1
- package/build/src/third_party/issue-descriptions/connectionAllowlistEmbeddingRequirementNotSatisfied.md +26 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistIFrameAttributeLoosensEmbeddingRequirement.md +19 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowConnectionAllowlistFrom.md +21 -0
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidAllowlistItemType.md +2 -2
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidHeader.md +2 -2
- package/build/src/third_party/issue-descriptions/connectionAllowlistInvalidUrlPattern.md +3 -3
- package/build/src/third_party/issue-descriptions/connectionAllowlistItemNotInnerList.md +2 -2
- package/build/src/third_party/issue-descriptions/connectionAllowlistMoreThanOneList.md +2 -2
- package/build/src/third_party/issue-descriptions/connectionAllowlistReportingEndpointNotToken.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieCrossSiteRedirectDowngrade.md +3 -3
- package/build/src/third_party/issue-descriptions/cookieExcludeBlockedWithinRelatedWebsiteSet.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieExcludePortMismatch.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieExcludeSchemeMismatch.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieExcludeThirdPartyPhaseoutSet.md +1 -1
- package/build/src/third_party/issue-descriptions/cookieWarnThirdPartyPhaseoutRead.md +1 -1
- package/build/src/third_party/issue-descriptions/corsAllowCredentialsRequired.md +1 -1
- package/build/src/third_party/issue-descriptions/corsDisabledScheme.md +2 -2
- package/build/src/third_party/issue-descriptions/corsDisallowedByMode.md +2 -2
- package/build/src/third_party/issue-descriptions/corsHeaderDisallowedByPreflightResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/corsInvalidHeaderValues.md +3 -3
- package/build/src/third_party/issue-descriptions/corsLocalNetworkAccessPermissionDenied.md +1 -1
- package/build/src/third_party/issue-descriptions/corsMethodDisallowedByPreflightResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/corsNoCorsRedirectModeNotFollow.md +1 -1
- package/build/src/third_party/issue-descriptions/corsOriginMismatch.md +3 -3
- package/build/src/third_party/issue-descriptions/corsPreflightResponseInvalid.md +2 -2
- package/build/src/third_party/issue-descriptions/corsRedirectContainsCredentials.md +3 -3
- package/build/src/third_party/issue-descriptions/corsWildcardOriginNotAllowed.md +4 -3
- package/build/src/third_party/issue-descriptions/cspEvalViolation.md +4 -4
- package/build/src/third_party/issue-descriptions/cspInlineViolation.md +2 -2
- package/build/src/third_party/issue-descriptions/cspTrustedTypesPolicyViolation.md +2 -2
- package/build/src/third_party/issue-descriptions/cspTrustedTypesSinkViolation.md +4 -4
- package/build/src/third_party/issue-descriptions/cspURLViolation.md +4 -4
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsEmptyList.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestAccountsNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsFetchFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestDnsInvalidRecord.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestEmailVerificationWellKnownNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestInvalidEmail.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestJwksInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestKeyBindingSigningFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestRpOriginIsOpaque.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenInvalidSdJwt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenMalformedSdJwt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidAudience.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidIssuedAt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidNonce.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidSdHash.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbInvalidTyp.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingAud.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingCnf.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingIat.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingNonce.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbMissingSdHash.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationKbSignatureFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmail.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidEmailVerified.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidHolderKey.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuedAt.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtInvalidIssuer.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtJwksMissingKeys.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingCnf.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingEmail.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIat.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtMissingIss.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtSignatureFailed.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestTokenVerificationSdJwtUnsupportedHeaderAlg.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestUserLoggedOut.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownAccountsEndpointCrossOrigin.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownHttpNotFound.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidContentType.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownInvalidResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownIssuanceEndpointCrossOrigin.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownListEmpty.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingAccountsEndpoint.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownMissingIssuanceEndpoint.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownNoResponse.md +1 -0
- package/build/src/third_party/issue-descriptions/emailVerificationRequestWellKnownUnsupportedSigningAlgorithm.md +1 -0
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsHttpNotFound.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsInvalidResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestAccountsNoResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestApprovalDeclined.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestCanceled.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorFetchingSignin.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestErrorIdToken.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenHttpNotFound.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestInvalidSigninResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestHttpNotFound.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestInvalidResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestManifestNoResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthRequestTooManyRequests.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidAccountsResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestInvalidConfigOrWellKnown.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoAccountSharingPermission.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoApiPermission.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNoReturningUserFromFetchedAccounts.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotIframe.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotPotentiallyTrustworthy.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSameOrigin.md +1 -1
- package/build/src/third_party/issue-descriptions/federatedAuthUserInfoRequestNotSignedInWithIdp.md +1 -1
- package/build/src/third_party/issue-descriptions/fetchingPartitionedBlobURL.md +2 -2
- package/build/src/third_party/issue-descriptions/genericBackUINavigationWouldSkipAd.md +4 -0
- package/build/src/third_party/issue-descriptions/genericFormAriaLabelledByToNonExistingIdError.md +2 -2
- package/build/src/third_party/issue-descriptions/genericFormAutocompleteAttributeEmptyError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormDuplicateIdForInputError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormEmptyIdAndNameAttributesForInputError.md +2 -2
- package/build/src/third_party/issue-descriptions/genericFormInputAssignedAutocompleteValueToIdOrNameAttributeError.md +2 -2
- package/build/src/third_party/issue-descriptions/genericFormInputHasWrongButWellIntendedAutocompleteValueError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormInputWithNoLabelError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormLabelForMatchesNonExistingIdError.md +2 -2
- package/build/src/third_party/issue-descriptions/genericFormLabelForNameError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormLabelHasNeitherForNorNestedInputError.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +1 -1
- package/build/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +1 -1
- package/build/src/third_party/issue-descriptions/genericNavigationEntryMarkedSkippable.md +2 -2
- package/build/src/third_party/issue-descriptions/heavyAd.md +1 -1
- package/build/src/third_party/issue-descriptions/lazyLoadImageZeroSize.md +7 -0
- package/build/src/third_party/issue-descriptions/navigatingPartitionedBlobURL.md +3 -3
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabled.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluder.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementActivationDisabledWithOccluderParent.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementFencedFrameDisallowed.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooLarge.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementFontSizeTooSmall.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementInsetBoxShadowUnsupported.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementInvalidDisplayStyle.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementInvalidSizeValue.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementInvalidType.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementInvalidTypeActivation.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementNonOpaqueColor.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementPaddingBottomUnsupported.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementPaddingRightUnsupported.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementRequestInProgress.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementSecurityChecksFailed.md +1 -1
- package/build/src/third_party/issue-descriptions/permissionElementTypeNotSupported.md +2 -2
- package/build/src/third_party/issue-descriptions/permissionElementUntrustedEvent.md +1 -1
- package/build/src/third_party/issue-descriptions/placeholderDescriptionForInvisibleIssues.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedOptGroupChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityDisallowedSelectChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentAttributesSelectDescendant.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentLegendChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityInteractiveContentOptionChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectElementAccessibilityNonPhrasingContentOptionChild.md +1 -1
- package/build/src/third_party/issue-descriptions/selectivePermissionsIntervention.md +3 -3
- package/build/src/third_party/issue-descriptions/sharedArrayBuffer.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorCrossOriginNoCorsRequest.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorMatchingDictionaryNotUsed.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorCossOriginNoCorsRequest.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorDisallowedBySettings.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorExpiredResponse.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorFeatureDisabled.md +2 -2
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorInvalidStructuredHeader.md +1 -1
- package/build/src/third_party/issue-descriptions/sharedDictionaryWriteErrorNavigationRequest.md +2 -2
- package/build/src/third_party/issue-descriptions/sriInvalidSignatureHeader.md +4 -4
- package/build/src/third_party/issue-descriptions/sriInvalidSignatureInputHeader.md +4 -4
- package/build/src/third_party/issue-descriptions/sriMissingSignatureHeader.md +1 -1
- package/build/src/third_party/issue-descriptions/sriMissingSignatureInputHeader.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsIncorrectLength.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsNotByteSequence.md +4 -4
- package/build/src/third_party/issue-descriptions/sriSignatureHeaderValueIsParameterized.md +4 -4
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentName.md +1 -1
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidComponentType.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidDerivedComponentParameter.md +1 -1
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidHeaderComponentParameter.md +1 -1
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderInvalidParameter.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderKeyIdLength.md +5 -5
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingLabel.md +3 -3
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderMissingRequiredParameters.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueMissingComponents.md +2 -2
- package/build/src/third_party/issue-descriptions/sriSignatureInputHeaderValueNotInnerList.md +2 -2
- package/build/src/third_party/issue-descriptions/sriValidationFailedIntegrityMismatch.md +4 -4
- package/build/src/third_party/issue-descriptions/sriValidationFailedInvalidLength.md +3 -3
- package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureExpired.md +2 -2
- package/build/src/third_party/issue-descriptions/sriValidationFailedSignatureMismatch.md +2 -2
- package/build/src/third_party/issue-descriptions/stylesheetLateImport.md +1 -1
- package/build/src/third_party/issue-descriptions/summaryElementAccessibilityInteractiveContentSummaryDescendant.md +1 -1
- package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestLength.md +2 -2
- package/build/src/third_party/issue-descriptions/unencodedDigestIncorrectDigestType.md +3 -3
- package/build/src/third_party/issue-descriptions/unencodedDigestMalformedDictionary.md +2 -2
- package/build/src/third_party/issue-descriptions/unencodedDigestUnknownAlgorithm.md +1 -1
- package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +3177 -6340
- package/build/src/tools/ToolDefinition.js +2 -2
- package/build/src/tools/categories.js +3 -0
- package/build/src/tools/console.js +13 -0
- package/build/src/tools/emulation.js +30 -3
- package/build/src/tools/extensions.js +8 -1
- package/build/src/tools/input.js +246 -128
- package/build/src/tools/lighthouse.js +14 -7
- package/build/src/tools/memory.js +289 -25
- package/build/src/tools/network.js +10 -7
- package/build/src/tools/pages.js +33 -92
- package/build/src/tools/performance.js +67 -52
- package/build/src/tools/pwa.js +128 -0
- package/build/src/tools/screencast.js +35 -12
- package/build/src/tools/screenshot.js +234 -75
- package/build/src/tools/script.js +130 -45
- package/build/src/tools/slim/tools.js +3 -0
- package/build/src/tools/snapshot.js +7 -4
- package/build/src/tools/thirdPartyDeveloper.js +19 -9
- package/build/src/tools/tools.js +3 -1
- package/build/src/tools/webmcp.js +3 -1
- package/build/src/utils/WaitForHelper.js +299 -0
- package/build/src/utils/check-for-updates.js +8 -2
- package/build/src/utils/files.js +42 -3
- package/build/src/utils/logger.js +51 -0
- package/build/src/utils/polyfill.js +11 -0
- package/build/src/utils/url.js +43 -0
- package/build/src/version.js +1 -1
- package/package.json +42 -33
- package/build/src/DevToolsConnectionAdapter.js +0 -70
- package/build/src/HeapSnapshotManager.js +0 -110
- package/build/src/Mutex.js +0 -38
- package/build/src/WaitForHelper.js +0 -195
- package/build/src/bin/cliDefinitions.js +0 -616
- package/build/src/logger.js +0 -37
- package/build/src/polyfill.js +0 -8
- package/build/src/telemetry/metricUtils.js +0 -15
- package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeRead.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteExcludeContextDowngradeSet.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteExcludeNavigationContextDowngrade.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeRead.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteWarnCrossDowngradeSet.md +0 -8
- package/build/src/third_party/issue-descriptions/SameSiteWarnStrictLaxDowngradeStrict.md +0 -8
- package/build/src/third_party/issue-descriptions/arInsecureContext.md +0 -7
- package/build/src/third_party/issue-descriptions/arInvalidInfoHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterOsSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterOsTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arInvalidRegisterTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNavigationRegistrationUniqueScopeAlreadySet.md +0 -5
- package/build/src/third_party/issue-descriptions/arNavigationRegistrationWithoutTransientUserActivation.md +0 -6
- package/build/src/third_party/issue-descriptions/arNoRegisterOsSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoRegisterOsTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoRegisterSourceHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoRegisterTriggerHeader.md +0 -5
- package/build/src/third_party/issue-descriptions/arNoWebOrOsSupport.md +0 -4
- package/build/src/third_party/issue-descriptions/arOsSourceIgnored.md +0 -18
- package/build/src/third_party/issue-descriptions/arOsTriggerIgnored.md +0 -19
- package/build/src/third_party/issue-descriptions/arPermissionPolicyDisabled.md +0 -8
- package/build/src/third_party/issue-descriptions/arSourceAndTriggerHeaders.md +0 -9
- package/build/src/third_party/issue-descriptions/arSourceIgnored.md +0 -13
- package/build/src/third_party/issue-descriptions/arTriggerIgnored.md +0 -12
- package/build/src/third_party/issue-descriptions/arUntrustworthyReportingOrigin.md +0 -10
- package/build/src/third_party/issue-descriptions/arWebAndOsHeaders.md +0 -11
- package/build/src/utils/string.js +0 -37
- package/build/src/utils/types.js +0 -7
package/build/src/browser.js
CHANGED
|
@@ -9,9 +9,10 @@ import { execSync } from 'node:child_process';
|
|
|
9
9
|
import fs from 'node:fs';
|
|
10
10
|
import os from 'node:os';
|
|
11
11
|
import path from 'node:path';
|
|
12
|
-
import { logger } from './logger.js';
|
|
13
12
|
import { puppeteer } from './third_party/index.js';
|
|
13
|
+
import { logger, puppeteerLogger } from './utils/logger.js';
|
|
14
14
|
let browser;
|
|
15
|
+
let browserMode;
|
|
15
16
|
function makeTargetFilter(enableExtensions = false) {
|
|
16
17
|
const ignoredPrefixes = new Set(['chrome://', 'chrome-untrusted://']);
|
|
17
18
|
if (!enableExtensions) {
|
|
@@ -42,6 +43,9 @@ export async function ensureBrowserConnected(options) {
|
|
|
42
43
|
targetFilter: makeTargetFilter(enableExtensions),
|
|
43
44
|
defaultViewport: null,
|
|
44
45
|
handleDevToolsAsPage: true,
|
|
46
|
+
blocklist: options.blocklist,
|
|
47
|
+
allowlist: options.allowlist,
|
|
48
|
+
logger: puppeteerLogger,
|
|
45
49
|
};
|
|
46
50
|
let autoConnect = false;
|
|
47
51
|
if (options.wsEndpoint) {
|
|
@@ -95,16 +99,21 @@ export async function ensureBrowserConnected(options) {
|
|
|
95
99
|
else {
|
|
96
100
|
throw new Error('Either browserURL, wsEndpoint, channel or userDataDir must be provided');
|
|
97
101
|
}
|
|
98
|
-
logger('Connecting Puppeteer to ', JSON.stringify(connectOptions));
|
|
102
|
+
logger?.('Connecting Puppeteer to ', JSON.stringify(connectOptions));
|
|
99
103
|
try {
|
|
100
|
-
browser
|
|
104
|
+
// Assign mode before browser so a concurrent closeBrowser() never sees
|
|
105
|
+
// `browser` set with `browserMode` still undefined (would fall through
|
|
106
|
+
// to the disconnect() path and orphan a launched Chrome).
|
|
107
|
+
const connected = await puppeteer.connect(connectOptions);
|
|
108
|
+
browserMode = 'connected';
|
|
109
|
+
browser = connected;
|
|
101
110
|
}
|
|
102
111
|
catch (err) {
|
|
103
112
|
throw new Error(`Could not connect to Chrome. ${autoConnect ? `Check if Chrome is running and remote debugging is enabled by going to chrome://inspect/#remote-debugging.` : `Check if Chrome is running.`}`, {
|
|
104
113
|
cause: err,
|
|
105
114
|
});
|
|
106
115
|
}
|
|
107
|
-
logger('Connected Puppeteer');
|
|
116
|
+
logger?.('Connected Puppeteer');
|
|
108
117
|
return browser;
|
|
109
118
|
}
|
|
110
119
|
export function detectDisplay() {
|
|
@@ -170,6 +179,9 @@ export async function launch(options) {
|
|
|
170
179
|
acceptInsecureCerts: options.acceptInsecureCerts,
|
|
171
180
|
handleDevToolsAsPage: true,
|
|
172
181
|
enableExtensions: options.enableExtensions,
|
|
182
|
+
blocklist: options.blocklist,
|
|
183
|
+
allowlist: options.allowlist,
|
|
184
|
+
logger: puppeteerLogger,
|
|
173
185
|
});
|
|
174
186
|
if (options.logFile) {
|
|
175
187
|
// FIXME: we are probably subscribing too late to catch startup logs. We
|
|
@@ -200,12 +212,40 @@ export async function ensureBrowserLaunched(options) {
|
|
|
200
212
|
if (browser?.connected) {
|
|
201
213
|
return browser;
|
|
202
214
|
}
|
|
203
|
-
browser
|
|
215
|
+
// Assign mode before browser; see the connect path above for rationale.
|
|
216
|
+
const launched = await launch(options);
|
|
217
|
+
browserMode = 'launched';
|
|
218
|
+
browser = launched;
|
|
204
219
|
return browser;
|
|
205
220
|
}
|
|
206
221
|
export function getCurrentBrowser() {
|
|
207
222
|
return browser;
|
|
208
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Shutdown hook for the active browser. Closes a launched browser (so the
|
|
226
|
+
* Chrome subprocess is reaped) or disconnects from an attached browser (so
|
|
227
|
+
* the user's Chrome instance stays alive). No-op if no browser is active or
|
|
228
|
+
* the connection has already been dropped. Called from the server entrypoint
|
|
229
|
+
* on stdin EOF / SIGTERM / SIGINT.
|
|
230
|
+
*/
|
|
231
|
+
export async function closeBrowser() {
|
|
232
|
+
const b = browser;
|
|
233
|
+
const mode = browserMode;
|
|
234
|
+
browser = undefined;
|
|
235
|
+
browserMode = undefined;
|
|
236
|
+
if (!b || !b.connected) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (mode === 'launched') {
|
|
240
|
+
await b.close().catch(err => {
|
|
241
|
+
logger?.('Failed to close browser', err);
|
|
242
|
+
});
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
await b.disconnect().catch(err => {
|
|
246
|
+
logger?.('Failed to disconnect from browser', err);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
209
249
|
export async function closeBrowserIfOpen() {
|
|
210
250
|
if (browser?.connected) {
|
|
211
251
|
try {
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { FakeIssuesManager } from '
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { FakeIssuesManager } from '../devtools/DevtoolsUtils.js';
|
|
7
|
+
import { DevTools } from '../third_party/index.js';
|
|
8
|
+
import { createIdGenerator, stableIdSymbol, } from '../utils/id.js';
|
|
9
|
+
import { logger } from '../utils/logger.js';
|
|
10
10
|
export class UncaughtError {
|
|
11
11
|
details;
|
|
12
12
|
targetId;
|
|
@@ -16,113 +16,59 @@ export class UncaughtError {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
export class PageCollector {
|
|
19
|
-
|
|
20
|
-
#
|
|
21
|
-
#listeners = new WeakMap();
|
|
19
|
+
pptrPage;
|
|
20
|
+
#listeners;
|
|
22
21
|
maxNavigationSaved = 3;
|
|
23
22
|
/**
|
|
24
23
|
* This maps a Page to a list of navigations with a sub-list
|
|
25
24
|
* of all collected resources.
|
|
26
25
|
* The newer navigations come first.
|
|
27
26
|
*/
|
|
28
|
-
storage =
|
|
29
|
-
constructor(
|
|
30
|
-
this
|
|
31
|
-
this.#listenersInitializer = listeners;
|
|
32
|
-
}
|
|
33
|
-
async init(pages) {
|
|
34
|
-
for (const page of pages) {
|
|
35
|
-
this.addPage(page);
|
|
36
|
-
}
|
|
37
|
-
this.#browser.on('targetcreated', this.#onTargetCreated);
|
|
38
|
-
this.#browser.on('targetdestroyed', this.#onTargetDestroyed);
|
|
39
|
-
}
|
|
40
|
-
dispose() {
|
|
41
|
-
this.#browser.off('targetcreated', this.#onTargetCreated);
|
|
42
|
-
this.#browser.off('targetdestroyed', this.#onTargetDestroyed);
|
|
43
|
-
}
|
|
44
|
-
#onTargetCreated = async (target) => {
|
|
45
|
-
try {
|
|
46
|
-
const page = await target.page();
|
|
47
|
-
if (!page) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
this.addPage(page);
|
|
51
|
-
}
|
|
52
|
-
catch (err) {
|
|
53
|
-
logger('Error getting a page for a target onTargetCreated', err);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
#onTargetDestroyed = async (target) => {
|
|
57
|
-
try {
|
|
58
|
-
const page = await target.page();
|
|
59
|
-
if (!page) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
this.cleanupPageDestroyed(page);
|
|
63
|
-
}
|
|
64
|
-
catch (err) {
|
|
65
|
-
logger('Error getting a page for a target onTargetDestroyed', err);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
addPage(page) {
|
|
69
|
-
this.#initializePage(page);
|
|
70
|
-
}
|
|
71
|
-
#initializePage(page) {
|
|
72
|
-
if (this.storage.has(page)) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
27
|
+
storage = [[]];
|
|
28
|
+
constructor(page, listeners, maxResourcesPerNavigation) {
|
|
29
|
+
this.pptrPage = page;
|
|
75
30
|
const idGenerator = createIdGenerator();
|
|
76
|
-
const
|
|
77
|
-
this.storage.set(page, storedLists);
|
|
78
|
-
const listeners = this.#listenersInitializer(value => {
|
|
31
|
+
const listenerMap = listeners(value => {
|
|
79
32
|
const withId = value;
|
|
80
33
|
withId[stableIdSymbol] = idGenerator();
|
|
81
|
-
|
|
82
|
-
|
|
34
|
+
this.storage[0].push(withId);
|
|
35
|
+
if (maxResourcesPerNavigation !== undefined &&
|
|
36
|
+
this.storage[0].length > maxResourcesPerNavigation) {
|
|
37
|
+
this.storage[0].splice(0, this.storage[0].length - maxResourcesPerNavigation);
|
|
38
|
+
}
|
|
83
39
|
});
|
|
84
|
-
|
|
40
|
+
listenerMap['framenavigated'] = (frame) => {
|
|
85
41
|
// Only split the storage on main frame navigation
|
|
86
|
-
if (frame !==
|
|
42
|
+
if (frame !== this.pptrPage.mainFrame()) {
|
|
87
43
|
return;
|
|
88
44
|
}
|
|
89
|
-
this.splitAfterNavigation(
|
|
45
|
+
this.splitAfterNavigation();
|
|
90
46
|
};
|
|
91
|
-
for (const [name, listener] of Object.entries(
|
|
92
|
-
|
|
47
|
+
for (const [name, listener] of Object.entries(listenerMap)) {
|
|
48
|
+
this.pptrPage.on(name, listener);
|
|
93
49
|
}
|
|
94
|
-
this.#listeners
|
|
50
|
+
this.#listeners = listenerMap;
|
|
95
51
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
// Add the latest navigation first
|
|
102
|
-
navigations.unshift([]);
|
|
103
|
-
navigations.splice(this.maxNavigationSaved);
|
|
104
|
-
}
|
|
105
|
-
cleanupPageDestroyed(page) {
|
|
106
|
-
const listeners = this.#listeners.get(page);
|
|
107
|
-
if (listeners) {
|
|
108
|
-
for (const [name, listener] of Object.entries(listeners)) {
|
|
109
|
-
page.off(name, listener);
|
|
52
|
+
dispose() {
|
|
53
|
+
if (this.#listeners) {
|
|
54
|
+
for (const [name, listener] of Object.entries(this.#listeners)) {
|
|
55
|
+
this.pptrPage.off(name, listener);
|
|
110
56
|
}
|
|
111
57
|
}
|
|
112
|
-
this.storage.delete(page);
|
|
113
58
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
59
|
+
splitAfterNavigation() {
|
|
60
|
+
// Add the latest navigation first
|
|
61
|
+
this.storage.unshift([]);
|
|
62
|
+
this.storage.splice(this.maxNavigationSaved);
|
|
63
|
+
}
|
|
64
|
+
getData(includePreservedData) {
|
|
119
65
|
if (!includePreservedData) {
|
|
120
|
-
return
|
|
66
|
+
return this.storage[0];
|
|
121
67
|
}
|
|
122
68
|
const data = [];
|
|
123
69
|
for (let index = this.maxNavigationSaved; index >= 0; index--) {
|
|
124
|
-
if (
|
|
125
|
-
data.push(...
|
|
70
|
+
if (this.storage[index]) {
|
|
71
|
+
data.push(...this.storage[index]);
|
|
126
72
|
}
|
|
127
73
|
}
|
|
128
74
|
return data;
|
|
@@ -130,23 +76,15 @@ export class PageCollector {
|
|
|
130
76
|
getIdForResource(resource) {
|
|
131
77
|
return resource[stableIdSymbol] ?? -1;
|
|
132
78
|
}
|
|
133
|
-
getById(
|
|
134
|
-
const
|
|
135
|
-
if (!
|
|
136
|
-
throw new Error('
|
|
137
|
-
}
|
|
138
|
-
const item = this.find(page, item => item[stableIdSymbol] === stableId);
|
|
139
|
-
if (item) {
|
|
140
|
-
return item;
|
|
79
|
+
getById(stableId) {
|
|
80
|
+
const item = this.find(item => item[stableIdSymbol] === stableId);
|
|
81
|
+
if (!item) {
|
|
82
|
+
throw new Error('Request not found for selected page');
|
|
141
83
|
}
|
|
142
|
-
|
|
84
|
+
return item;
|
|
143
85
|
}
|
|
144
|
-
find(
|
|
145
|
-
const
|
|
146
|
-
if (!navigations) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
for (const navigation of navigations) {
|
|
86
|
+
find(filter) {
|
|
87
|
+
for (const navigation of this.storage) {
|
|
150
88
|
const item = navigation.find(filter);
|
|
151
89
|
if (item) {
|
|
152
90
|
return item;
|
|
@@ -156,19 +94,15 @@ export class PageCollector {
|
|
|
156
94
|
}
|
|
157
95
|
}
|
|
158
96
|
export class ConsoleCollector extends PageCollector {
|
|
159
|
-
#
|
|
160
|
-
|
|
161
|
-
super
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
this.#subscribedPages.set(page, subscriber);
|
|
165
|
-
void subscriber.subscribe();
|
|
166
|
-
}
|
|
97
|
+
#subscriber;
|
|
98
|
+
constructor(page, listeners) {
|
|
99
|
+
super(page, listeners);
|
|
100
|
+
this.#subscriber = new PageEventSubscriber(this.pptrPage);
|
|
101
|
+
this.#subscriber.subscribe();
|
|
167
102
|
}
|
|
168
|
-
|
|
169
|
-
super.
|
|
170
|
-
this.#
|
|
171
|
-
this.#subscribedPages.delete(page);
|
|
103
|
+
dispose() {
|
|
104
|
+
super.dispose();
|
|
105
|
+
this.#subscriber?.unsubscribe();
|
|
172
106
|
}
|
|
173
107
|
}
|
|
174
108
|
class PageEventSubscriber {
|
|
@@ -194,7 +128,7 @@ class PageEventSubscriber {
|
|
|
194
128
|
this.#issueAggregator = new DevTools.IssueAggregator(this.#issueManager);
|
|
195
129
|
this.#issueAggregator.addEventListener("AggregatedIssueUpdated" /* DevTools.IssueAggregatorEvents.AGGREGATED_ISSUE_UPDATED */, this.#onAggregatedIssue);
|
|
196
130
|
}
|
|
197
|
-
|
|
131
|
+
subscribe() {
|
|
198
132
|
this.#resetIssueAggregator();
|
|
199
133
|
this.#page.on('framenavigated', this.#onFrameNavigated);
|
|
200
134
|
this.#page.on('issue', this.#onIssueAdded);
|
|
@@ -232,16 +166,16 @@ class PageEventSubscriber {
|
|
|
232
166
|
};
|
|
233
167
|
#onIssueAdded = (inspectorIssue) => {
|
|
234
168
|
try {
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
if (
|
|
169
|
+
// @ts-expect-error The types are missmatched but they
|
|
170
|
+
// are coming from CDP
|
|
171
|
+
if (!DevTools.isIssueCodeSupported(inspectorIssue.code)) {
|
|
238
172
|
return;
|
|
239
173
|
}
|
|
240
174
|
const issue = DevTools.createIssuesFromProtocolIssue(null,
|
|
241
175
|
// @ts-expect-error Protocol types diverge.
|
|
242
176
|
inspectorIssue)[0];
|
|
243
177
|
if (!issue) {
|
|
244
|
-
logger('No issue mapping for for the issue: ', inspectorIssue.code);
|
|
178
|
+
logger?.('No issue mapping for for the issue: ', inspectorIssue.code);
|
|
245
179
|
return;
|
|
246
180
|
}
|
|
247
181
|
const primaryKey = issue.primaryKey();
|
|
@@ -256,28 +190,25 @@ class PageEventSubscriber {
|
|
|
256
190
|
});
|
|
257
191
|
}
|
|
258
192
|
catch (error) {
|
|
259
|
-
logger('Error creating a new issue', error);
|
|
193
|
+
logger?.('Error creating a new issue', error);
|
|
260
194
|
}
|
|
261
195
|
};
|
|
262
196
|
}
|
|
263
197
|
export class NetworkCollector extends PageCollector {
|
|
264
|
-
|
|
198
|
+
static MAX_REQUESTS_PER_NAVIGATION = 1_000;
|
|
199
|
+
constructor(page, maxRequestsPerNavigation = NetworkCollector.MAX_REQUESTS_PER_NAVIGATION, listeners = collect => {
|
|
265
200
|
return {
|
|
266
201
|
request: req => {
|
|
267
202
|
collect(req);
|
|
268
203
|
},
|
|
269
204
|
};
|
|
270
205
|
}) {
|
|
271
|
-
super(
|
|
206
|
+
super(page, listeners, maxRequestsPerNavigation);
|
|
272
207
|
}
|
|
273
|
-
splitAfterNavigation(
|
|
274
|
-
const
|
|
275
|
-
if (!navigations) {
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
const requests = navigations[0];
|
|
208
|
+
splitAfterNavigation() {
|
|
209
|
+
const requests = this.storage[0];
|
|
279
210
|
const lastRequestIdx = requests.findLastIndex(request => {
|
|
280
|
-
return request.frame() ===
|
|
211
|
+
return request.frame() === this.pptrPage.mainFrame()
|
|
281
212
|
? request.isNavigationRequest()
|
|
282
213
|
: false;
|
|
283
214
|
});
|
|
@@ -286,12 +217,12 @@ export class NetworkCollector extends PageCollector {
|
|
|
286
217
|
// Keep the reference
|
|
287
218
|
if (lastRequestIdx !== -1) {
|
|
288
219
|
const fromCurrentNavigation = requests.splice(lastRequestIdx);
|
|
289
|
-
|
|
220
|
+
this.storage.unshift(fromCurrentNavigation);
|
|
290
221
|
}
|
|
291
222
|
else {
|
|
292
|
-
|
|
223
|
+
this.storage.unshift([]);
|
|
293
224
|
}
|
|
294
|
-
|
|
225
|
+
this.storage.splice(this.maxNavigationSaved);
|
|
295
226
|
}
|
|
296
227
|
}
|
|
297
228
|
//# sourceMappingURL=PageCollector.js.map
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { UncaughtError } from './PageCollector.js';
|
|
7
|
+
import { createIdGenerator, stableIdSymbol } from '../utils/id.js';
|
|
8
|
+
const CHROME_EXTENSION_PREFIX = 'chrome-extension://';
|
|
9
|
+
export class ServiceWorkerSubscriber {
|
|
10
|
+
#target;
|
|
11
|
+
#callback;
|
|
12
|
+
#session;
|
|
13
|
+
#worker;
|
|
14
|
+
constructor(target, callback) {
|
|
15
|
+
this.#target = target;
|
|
16
|
+
this.#callback = callback;
|
|
17
|
+
}
|
|
18
|
+
async subscribe() {
|
|
19
|
+
this.#session = await this.#target.createCDPSession();
|
|
20
|
+
await this.#session.send('Runtime.enable');
|
|
21
|
+
this.#session.on('Runtime.exceptionThrown', this.#onExceptionThrown);
|
|
22
|
+
this.#worker = (await this.#target.worker()) ?? undefined;
|
|
23
|
+
if (this.#worker) {
|
|
24
|
+
this.#worker.on('console', this.#onConsole);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async unsubscribe() {
|
|
28
|
+
if (this.#worker) {
|
|
29
|
+
this.#worker.off('console', this.#onConsole);
|
|
30
|
+
}
|
|
31
|
+
await this.#session?.detach();
|
|
32
|
+
}
|
|
33
|
+
#onConsole = (message) => {
|
|
34
|
+
this.#callback(message);
|
|
35
|
+
};
|
|
36
|
+
#onExceptionThrown = (event) => {
|
|
37
|
+
const url = this.#target.url();
|
|
38
|
+
const extensionId = extractExtensionId(url);
|
|
39
|
+
if (extensionId) {
|
|
40
|
+
this.#callback(new UncaughtError(event.exceptionDetails, extensionId));
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export class ServiceWorkerConsoleCollector {
|
|
45
|
+
#storage = new Map();
|
|
46
|
+
#maxLogs;
|
|
47
|
+
#browser;
|
|
48
|
+
#serviceWorkerSubscribers = new Map();
|
|
49
|
+
#idGenerator = createIdGenerator();
|
|
50
|
+
constructor(browser, maxLogs = 1000) {
|
|
51
|
+
this.#browser = browser;
|
|
52
|
+
this.#maxLogs = maxLogs;
|
|
53
|
+
}
|
|
54
|
+
async init(workers) {
|
|
55
|
+
if (!this.#browser) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.#browser.on('targetcreated', this.#onTargetCreated);
|
|
59
|
+
this.#browser.on('targetdestroyed', this.#onTargetDestroyed);
|
|
60
|
+
for (const worker of workers) {
|
|
61
|
+
void this.#onTargetCreated(worker.target);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
dispose() {
|
|
65
|
+
if (!this.#browser) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.#browser.off('targetcreated', this.#onTargetCreated);
|
|
69
|
+
this.#browser.off('targetdestroyed', this.#onTargetDestroyed);
|
|
70
|
+
for (const subscriber of this.#serviceWorkerSubscribers.values()) {
|
|
71
|
+
subscriber.unsubscribe().catch(err => {
|
|
72
|
+
if (err instanceof Error &&
|
|
73
|
+
!err.message.includes('Target closed') &&
|
|
74
|
+
!err.message.includes('Session closed')) {
|
|
75
|
+
// Swallow error as we are tearing down the system
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
this.#serviceWorkerSubscribers.clear();
|
|
80
|
+
}
|
|
81
|
+
#onTargetCreated = async (target) => {
|
|
82
|
+
if (this.#serviceWorkerSubscribers.has(target)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const origin = target.url();
|
|
86
|
+
if (target.type() === 'service_worker' && isExtensionOrigin(origin)) {
|
|
87
|
+
const extensionId = extractExtensionId(origin);
|
|
88
|
+
if (!extensionId) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const subscriber = new ServiceWorkerSubscriber(target, item => {
|
|
92
|
+
this.addLog(extensionId, item);
|
|
93
|
+
});
|
|
94
|
+
try {
|
|
95
|
+
await subscriber.subscribe();
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
if (err instanceof Error &&
|
|
99
|
+
!err.message.includes('Target closed') &&
|
|
100
|
+
!err.message.includes('Session closed')) {
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
this.#serviceWorkerSubscribers.set(target, subscriber);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
#onTargetDestroyed = async (target) => {
|
|
108
|
+
const subscriber = this.#serviceWorkerSubscribers.get(target);
|
|
109
|
+
if (subscriber) {
|
|
110
|
+
try {
|
|
111
|
+
await subscriber.unsubscribe();
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
if (err instanceof Error &&
|
|
115
|
+
!err.message.includes('Target closed') &&
|
|
116
|
+
!err.message.includes('Session closed')) {
|
|
117
|
+
throw err;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
this.#serviceWorkerSubscribers.delete(target);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
addLog(extensionId, log) {
|
|
124
|
+
const logs = this.#storage.get(extensionId) ?? [];
|
|
125
|
+
const withId = log;
|
|
126
|
+
withId[stableIdSymbol] = this.#idGenerator();
|
|
127
|
+
logs.push(withId);
|
|
128
|
+
if (logs.length > this.#maxLogs) {
|
|
129
|
+
logs.shift();
|
|
130
|
+
}
|
|
131
|
+
this.#storage.set(extensionId, logs);
|
|
132
|
+
}
|
|
133
|
+
getData(extensionId) {
|
|
134
|
+
return this.#storage.get(extensionId) ?? [];
|
|
135
|
+
}
|
|
136
|
+
getById(extensionId, stableId) {
|
|
137
|
+
const logs = this.#storage.get(extensionId);
|
|
138
|
+
if (!logs) {
|
|
139
|
+
throw new Error('No logs found for selected extension');
|
|
140
|
+
}
|
|
141
|
+
const item = logs.find(item => item[stableIdSymbol] === stableId);
|
|
142
|
+
if (item) {
|
|
143
|
+
return item;
|
|
144
|
+
}
|
|
145
|
+
throw new Error('Log not found for selected extension');
|
|
146
|
+
}
|
|
147
|
+
find(extensionId, filter) {
|
|
148
|
+
const logs = this.#storage.get(extensionId);
|
|
149
|
+
if (!logs) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
return logs.find(filter);
|
|
153
|
+
}
|
|
154
|
+
clearLogs(extensionId) {
|
|
155
|
+
this.#storage.delete(extensionId);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function extractExtensionId(origin) {
|
|
159
|
+
if (!origin || !isExtensionOrigin(origin)) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const pathPart = origin.substring(CHROME_EXTENSION_PREFIX.length);
|
|
163
|
+
const slashIndex = pathPart.indexOf('/');
|
|
164
|
+
// if there's no / it means that pathPart is now the extensionId, otherwise
|
|
165
|
+
// we take everything until the first /
|
|
166
|
+
return slashIndex === -1 ? pathPart : pathPart.substring(0, slashIndex);
|
|
167
|
+
}
|
|
168
|
+
function isExtensionOrigin(origin) {
|
|
169
|
+
return origin.startsWith(CHROME_EXTENSION_PREFIX);
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=ServiceWorkerCollector.js.map
|