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.
- package/README.md +108 -8
- 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 +614 -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 +116 -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 +193 -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 +7 -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 -4
- package/package.json +43 -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
|
@@ -5,124 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import process from 'node:process';
|
|
7
7
|
import { DAEMON_CLIENT_NAME } from '../daemon/utils.js';
|
|
8
|
-
import { logger } from '../logger.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
import { sanitizeParams, stripUnderscoreBeforeNumber } from './transformation.js';
|
|
9
10
|
import { McpClient, WatchdogMessageType, OsType, } from './types.js';
|
|
10
11
|
import { WatchdogClient } from './WatchdogClient.js';
|
|
11
12
|
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
12
|
-
export const PARAM_BLOCKLIST = new Set(['uid', 'reqid', 'msgid']);
|
|
13
|
-
const SUPPORTED_ZOD_TYPES = [
|
|
14
|
-
'ZodString',
|
|
15
|
-
'ZodNumber',
|
|
16
|
-
'ZodBoolean',
|
|
17
|
-
'ZodArray',
|
|
18
|
-
'ZodEnum',
|
|
19
|
-
];
|
|
20
|
-
function isZodType(type) {
|
|
21
|
-
return SUPPORTED_ZOD_TYPES.includes(type);
|
|
22
|
-
}
|
|
23
|
-
export function getZodType(zodType) {
|
|
24
|
-
const def = zodType._def;
|
|
25
|
-
const typeName = def.typeName;
|
|
26
|
-
if (typeName === 'ZodOptional' ||
|
|
27
|
-
typeName === 'ZodDefault' ||
|
|
28
|
-
typeName === 'ZodNullable') {
|
|
29
|
-
return getZodType(def.innerType);
|
|
30
|
-
}
|
|
31
|
-
if (typeName === 'ZodEffects') {
|
|
32
|
-
return getZodType(def.schema);
|
|
33
|
-
}
|
|
34
|
-
if (isZodType(typeName)) {
|
|
35
|
-
return typeName;
|
|
36
|
-
}
|
|
37
|
-
throw new Error(`Unsupported zod type for tool parameter: ${typeName}`);
|
|
38
|
-
}
|
|
39
|
-
export function transformArgName(zodType, name) {
|
|
40
|
-
const snakeCaseName = name.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
|
41
|
-
if (zodType === 'ZodString') {
|
|
42
|
-
return `${snakeCaseName}_length`;
|
|
43
|
-
}
|
|
44
|
-
else if (zodType === 'ZodArray') {
|
|
45
|
-
return `${snakeCaseName}_count`;
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
return snakeCaseName;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
export function transformArgType(zodType) {
|
|
52
|
-
if (zodType === 'ZodString' || zodType === 'ZodArray') {
|
|
53
|
-
return 'number';
|
|
54
|
-
}
|
|
55
|
-
switch (zodType) {
|
|
56
|
-
case 'ZodNumber':
|
|
57
|
-
return 'number';
|
|
58
|
-
case 'ZodBoolean':
|
|
59
|
-
return 'boolean';
|
|
60
|
-
case 'ZodEnum':
|
|
61
|
-
return 'enum';
|
|
62
|
-
default:
|
|
63
|
-
throw new Error(`Unsupported zod type for tool parameter: ${zodType}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
const BUCKETS = [
|
|
67
|
-
0, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000,
|
|
68
|
-
];
|
|
69
|
-
function bucketize(value) {
|
|
70
|
-
for (const bucket of BUCKETS) {
|
|
71
|
-
if (bucket >= value) {
|
|
72
|
-
return bucket;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return BUCKETS[BUCKETS.length - 1];
|
|
76
|
-
}
|
|
77
|
-
function transformValue(zodType, value) {
|
|
78
|
-
if (zodType === 'ZodString') {
|
|
79
|
-
return bucketize(value.length);
|
|
80
|
-
}
|
|
81
|
-
else if (zodType === 'ZodArray') {
|
|
82
|
-
return value.length;
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
return value;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function hasEquivalentType(zodType, value) {
|
|
89
|
-
if (zodType === 'ZodString') {
|
|
90
|
-
return typeof value === 'string';
|
|
91
|
-
}
|
|
92
|
-
else if (zodType === 'ZodArray') {
|
|
93
|
-
return Array.isArray(value);
|
|
94
|
-
}
|
|
95
|
-
else if (zodType === 'ZodNumber') {
|
|
96
|
-
return typeof value === 'number';
|
|
97
|
-
}
|
|
98
|
-
else if (zodType === 'ZodBoolean') {
|
|
99
|
-
return typeof value === 'boolean';
|
|
100
|
-
}
|
|
101
|
-
else if (zodType === 'ZodEnum') {
|
|
102
|
-
return (typeof value === 'string' ||
|
|
103
|
-
typeof value === 'number' ||
|
|
104
|
-
typeof value === 'boolean');
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
export function sanitizeParams(params, schema) {
|
|
111
|
-
const transformed = {};
|
|
112
|
-
for (const [name, value] of Object.entries(params)) {
|
|
113
|
-
if (PARAM_BLOCKLIST.has(name)) {
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
const zodType = getZodType(schema[name]);
|
|
117
|
-
if (!hasEquivalentType(zodType, value)) {
|
|
118
|
-
throw new Error(`parameter ${name} has type ${zodType} but value ${value} is not of equivalent type`);
|
|
119
|
-
}
|
|
120
|
-
const transformedName = transformArgName(zodType, name);
|
|
121
|
-
const transformedValue = transformValue(zodType, value);
|
|
122
|
-
transformed[transformedName] = transformedValue;
|
|
123
|
-
}
|
|
124
|
-
return transformed;
|
|
125
|
-
}
|
|
126
13
|
function detectOsType() {
|
|
127
14
|
switch (process.platform) {
|
|
128
15
|
case 'win32':
|
|
@@ -194,14 +81,18 @@ export class ClearcutLogger {
|
|
|
194
81
|
}
|
|
195
82
|
}
|
|
196
83
|
async logToolInvocation(args) {
|
|
84
|
+
const sanitizedToolName = stripUnderscoreBeforeNumber(args.toolName);
|
|
197
85
|
const tool_invocation = {
|
|
198
|
-
tool_name:
|
|
86
|
+
tool_name: sanitizedToolName,
|
|
199
87
|
success: args.success,
|
|
200
88
|
latency_ms: args.latencyMs,
|
|
201
89
|
};
|
|
90
|
+
if (Object.keys(args.context).length > 0) {
|
|
91
|
+
tool_invocation.context = args.context;
|
|
92
|
+
}
|
|
202
93
|
if (Object.keys(args.params).length > 0) {
|
|
203
94
|
tool_invocation.tool_params = {
|
|
204
|
-
[`${
|
|
95
|
+
[`${sanitizedToolName}_params`]: sanitizeParams(args.params, args.schema),
|
|
205
96
|
};
|
|
206
97
|
}
|
|
207
98
|
this.#watchdog.send({
|
|
@@ -248,7 +139,7 @@ export class ClearcutLogger {
|
|
|
248
139
|
}
|
|
249
140
|
}
|
|
250
141
|
catch (err) {
|
|
251
|
-
logger('Error in logDailyActiveIfNeeded:', err);
|
|
142
|
+
logger?.('Error in logDailyActiveIfNeeded:', err);
|
|
252
143
|
}
|
|
253
144
|
}
|
|
254
145
|
async logServerError(args) {
|
|
@@ -257,7 +148,9 @@ export class ClearcutLogger {
|
|
|
257
148
|
payload: {
|
|
258
149
|
mcp_client: this.#mcpClient,
|
|
259
150
|
server_error: {
|
|
260
|
-
tool_name: args.toolName
|
|
151
|
+
tool_name: args.toolName
|
|
152
|
+
? stripUnderscoreBeforeNumber(args.toolName)
|
|
153
|
+
: '',
|
|
261
154
|
error_code: args.errorCode,
|
|
262
155
|
},
|
|
263
156
|
},
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
import { logger } from '../logger.js';
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
9
|
export class WatchdogClient {
|
|
10
10
|
#childProcess;
|
|
11
11
|
constructor(config, options) {
|
|
@@ -35,10 +35,10 @@ export class WatchdogClient {
|
|
|
35
35
|
});
|
|
36
36
|
this.#childProcess.unref();
|
|
37
37
|
this.#childProcess.on('error', err => {
|
|
38
|
-
logger('Watchdog process error:', err);
|
|
38
|
+
logger?.('Watchdog process error:', err);
|
|
39
39
|
});
|
|
40
40
|
this.#childProcess.on('exit', (code, signal) => {
|
|
41
|
-
logger(`Watchdog exited with code ${code} and signal ${signal}`);
|
|
41
|
+
logger?.(`Watchdog exited with code ${code} and signal ${signal}`);
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
send(message) {
|
|
@@ -50,11 +50,11 @@ export class WatchdogClient {
|
|
|
50
50
|
this.#childProcess.stdin.write(line);
|
|
51
51
|
}
|
|
52
52
|
catch (err) {
|
|
53
|
-
logger('Failed to write to watchdog stdin', err);
|
|
53
|
+
logger?.('Failed to write to watchdog stdin', err);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
else {
|
|
57
|
-
logger('Watchdog stdin not available, dropping message');
|
|
57
|
+
logger?.('Watchdog stdin not available, dropping message');
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -13,6 +13,6 @@ export var ErrorCode;
|
|
|
13
13
|
(function (ErrorCode) {
|
|
14
14
|
ErrorCode[ErrorCode["ERROR_CODE_UNSPECIFIED"] = 0] = "ERROR_CODE_UNSPECIFIED";
|
|
15
15
|
ErrorCode[ErrorCode["ERROR_CODE_PERSISTENCE_FILE_READ_FAILED"] = 1] = "ERROR_CODE_PERSISTENCE_FILE_READ_FAILED";
|
|
16
|
-
ErrorCode[ErrorCode["ERROR_CODE_PERSISTENCE_FILE_SAVE_FAILED"] =
|
|
16
|
+
ErrorCode[ErrorCode["ERROR_CODE_PERSISTENCE_FILE_SAVE_FAILED"] = 2] = "ERROR_CODE_PERSISTENCE_FILE_SAVE_FAILED";
|
|
17
17
|
})(ErrorCode || (ErrorCode = {}));
|
|
18
18
|
//# sourceMappingURL=errors.js.map
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
* @license
|
|
3
3
|
* Copyright 2026 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*
|
|
6
|
-
* Modified by Opera Software AS.
|
|
7
5
|
*/
|
|
8
|
-
import {
|
|
6
|
+
import { DevTools } from '../third_party/index.js';
|
|
7
|
+
import { stripUnderscoreBeforeNumber } from './transformation.js';
|
|
8
|
+
const { StringUtilities } = DevTools.Platform;
|
|
9
9
|
/**
|
|
10
10
|
* For enums, log the value as uppercase.
|
|
11
11
|
* We're going to have an enum for such flags with choices represented
|
|
12
12
|
* as an `enum` where the keys of the enum will map to the uppercase `choice`.
|
|
13
13
|
*/
|
|
14
14
|
function formatEnumChoice(snakeCaseName, choice) {
|
|
15
|
-
return `${snakeCaseName}_${choice}
|
|
15
|
+
return stripUnderscoreBeforeNumber(`${snakeCaseName}_${choice}`).toUpperCase();
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Computes telemetry flag usage from parsed arguments and CLI options.
|
|
@@ -31,7 +31,7 @@ export function computeFlagUsage(args, options) {
|
|
|
31
31
|
const usage = {};
|
|
32
32
|
for (const [flagName, config] of Object.entries(options)) {
|
|
33
33
|
const value = args[flagName];
|
|
34
|
-
const snakeCaseName = toSnakeCase(flagName);
|
|
34
|
+
const snakeCaseName = stripUnderscoreBeforeNumber(StringUtilities.toSnakeCase(flagName));
|
|
35
35
|
// If there isn't a default value provided for the flag,
|
|
36
36
|
// we're going to log whether it's present on the args user
|
|
37
37
|
// provided or not. If there is a default value, we only log presence
|
|
@@ -60,7 +60,7 @@ export function computeFlagUsage(args, options) {
|
|
|
60
60
|
export function getPossibleFlagMetrics(options) {
|
|
61
61
|
const metrics = [];
|
|
62
62
|
for (const [flagName, config] of Object.entries(options)) {
|
|
63
|
-
const snakeCaseName = toSnakeCase(flagName);
|
|
63
|
+
const snakeCaseName = stripUnderscoreBeforeNumber(StringUtilities.toSnakeCase(flagName));
|
|
64
64
|
// _present is always a possible metric
|
|
65
65
|
metrics.push({
|
|
66
66
|
name: `${snakeCaseName}_present`,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Copyright 2026 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { transformArgName, transformArgType, getZodType, PARAM_BLOCKLIST, } from './
|
|
6
|
+
import { transformArgName, transformArgType, getZodType, getEnumValues, PARAM_BLOCKLIST, stripUnderscoreBeforeNumber, } from './transformation.js';
|
|
7
7
|
/**
|
|
8
8
|
* Validates that all values in an enum are of the homogeneous primitive type.
|
|
9
9
|
* Returns the primitive type string. Throws an error if heterogeneous.
|
|
@@ -66,14 +66,7 @@ export function generateToolMetrics(tools) {
|
|
|
66
66
|
const transformedName = transformArgName(zodType, name);
|
|
67
67
|
let argType = transformArgType(zodType);
|
|
68
68
|
if (argType === 'enum') {
|
|
69
|
-
|
|
70
|
-
if (schema._def.values?.length > 0) {
|
|
71
|
-
values = schema._def.values;
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
values = schema._def.innerType._def.values;
|
|
75
|
-
}
|
|
76
|
-
argType = validateEnumHomogeneity(values);
|
|
69
|
+
argType = validateEnumHomogeneity(getEnumValues(schema));
|
|
77
70
|
}
|
|
78
71
|
args.push({
|
|
79
72
|
name: transformedName,
|
|
@@ -81,9 +74,9 @@ export function generateToolMetrics(tools) {
|
|
|
81
74
|
});
|
|
82
75
|
}
|
|
83
76
|
return {
|
|
84
|
-
name: tool.name,
|
|
77
|
+
name: stripUnderscoreBeforeNumber(tool.name),
|
|
85
78
|
args,
|
|
86
79
|
};
|
|
87
80
|
});
|
|
88
81
|
}
|
|
89
|
-
//# sourceMappingURL=
|
|
82
|
+
//# sourceMappingURL=metricsRegistry.js.map
|
|
@@ -7,7 +7,7 @@ import fs from 'node:fs/promises';
|
|
|
7
7
|
import os from 'node:os';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import process from 'node:process';
|
|
10
|
-
import { logger } from '../logger.js';
|
|
10
|
+
import { logger } from '../utils/logger.js';
|
|
11
11
|
import { ClearcutLogger } from './ClearcutLogger.js';
|
|
12
12
|
import { ErrorCode } from './errors.js';
|
|
13
13
|
const STATE_FILE_NAME = 'telemetry_state.json';
|
|
@@ -45,7 +45,7 @@ export class FilePersistence {
|
|
|
45
45
|
return JSON.parse(content);
|
|
46
46
|
}
|
|
47
47
|
catch (error) {
|
|
48
|
-
logger(`Failed to read telemetry state from ${filePath}:`, error);
|
|
48
|
+
logger?.(`Failed to read telemetry state from ${filePath}:`, error);
|
|
49
49
|
void ClearcutLogger.get()?.logServerError({
|
|
50
50
|
errorCode: ErrorCode.ERROR_CODE_PERSISTENCE_FILE_READ_FAILED,
|
|
51
51
|
});
|
|
@@ -62,7 +62,7 @@ export class FilePersistence {
|
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
64
64
|
// Ignore errors during state saving to avoid crashing the server
|
|
65
|
-
logger(`Failed to save telemetry state to ${filePath}:`, error);
|
|
65
|
+
logger?.(`Failed to save telemetry state to ${filePath}:`, error);
|
|
66
66
|
void ClearcutLogger.get()?.logServerError({
|
|
67
67
|
errorCode: ErrorCode.ERROR_CODE_PERSISTENCE_FILE_SAVE_FAILED,
|
|
68
68
|
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { isLocalhost } from '../utils/url.js';
|
|
7
|
+
const LATENCY_BUCKETS = [50, 100, 250, 500, 1000, 2500, 5000, 10000];
|
|
8
|
+
export function bucketizeLatency(latencyMs) {
|
|
9
|
+
for (const bucket of LATENCY_BUCKETS) {
|
|
10
|
+
if (latencyMs <= bucket) {
|
|
11
|
+
return bucket;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return LATENCY_BUCKETS[LATENCY_BUCKETS.length - 1];
|
|
15
|
+
}
|
|
16
|
+
export const PARAM_BLOCKLIST = new Set(['uid', 'reqid', 'msgid']);
|
|
17
|
+
const SUPPORTED_ZOD_TYPES = [
|
|
18
|
+
'ZodString',
|
|
19
|
+
'ZodNumber',
|
|
20
|
+
'ZodBoolean',
|
|
21
|
+
'ZodArray',
|
|
22
|
+
'ZodEnum',
|
|
23
|
+
'ZodRecord',
|
|
24
|
+
];
|
|
25
|
+
function isZodType(type) {
|
|
26
|
+
return SUPPORTED_ZOD_TYPES.includes(type);
|
|
27
|
+
}
|
|
28
|
+
export function getZodType(zodType) {
|
|
29
|
+
const def = zodType._def;
|
|
30
|
+
const typeName = def.typeName;
|
|
31
|
+
if (typeName === 'ZodOptional' ||
|
|
32
|
+
typeName === 'ZodDefault' ||
|
|
33
|
+
typeName === 'ZodNullable') {
|
|
34
|
+
return getZodType(def.innerType);
|
|
35
|
+
}
|
|
36
|
+
if (typeName === 'ZodEffects') {
|
|
37
|
+
return getZodType(def.schema);
|
|
38
|
+
}
|
|
39
|
+
if (isZodType(typeName)) {
|
|
40
|
+
return typeName;
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`Unsupported zod type for tool parameter: ${typeName}`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolves the values of an enum parameter, unwrapping any optional/default/
|
|
46
|
+
* nullable/effects wrappers (in any order), mirroring {@link getZodType}.
|
|
47
|
+
*/
|
|
48
|
+
export function getEnumValues(zodType) {
|
|
49
|
+
const def = zodType._def;
|
|
50
|
+
const typeName = def.typeName;
|
|
51
|
+
if (typeName === 'ZodOptional' ||
|
|
52
|
+
typeName === 'ZodDefault' ||
|
|
53
|
+
typeName === 'ZodNullable') {
|
|
54
|
+
return getEnumValues(def.innerType);
|
|
55
|
+
}
|
|
56
|
+
if (typeName === 'ZodEffects') {
|
|
57
|
+
return getEnumValues(def.schema);
|
|
58
|
+
}
|
|
59
|
+
if (typeName === 'ZodEnum') {
|
|
60
|
+
return def.values;
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`Cannot resolve enum values for zod type: ${typeName}`);
|
|
63
|
+
}
|
|
64
|
+
export function stripUnderscoreBeforeNumber(name) {
|
|
65
|
+
return name.replace(/_([0-9])/g, '$1');
|
|
66
|
+
}
|
|
67
|
+
export function transformArgName(zodType, name) {
|
|
68
|
+
const snakeCaseName = name.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
|
69
|
+
let transformed;
|
|
70
|
+
if (zodType === 'ZodString') {
|
|
71
|
+
transformed = `${snakeCaseName}_length`;
|
|
72
|
+
}
|
|
73
|
+
else if (zodType === 'ZodArray' || zodType === 'ZodRecord') {
|
|
74
|
+
transformed = `${snakeCaseName}_count`;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
transformed = snakeCaseName;
|
|
78
|
+
}
|
|
79
|
+
return stripUnderscoreBeforeNumber(transformed);
|
|
80
|
+
}
|
|
81
|
+
export function transformArgType(zodType) {
|
|
82
|
+
if (zodType === 'ZodString' ||
|
|
83
|
+
zodType === 'ZodArray' ||
|
|
84
|
+
zodType === 'ZodRecord') {
|
|
85
|
+
return 'number';
|
|
86
|
+
}
|
|
87
|
+
switch (zodType) {
|
|
88
|
+
case 'ZodNumber':
|
|
89
|
+
return 'number';
|
|
90
|
+
case 'ZodBoolean':
|
|
91
|
+
return 'boolean';
|
|
92
|
+
case 'ZodEnum':
|
|
93
|
+
return 'enum';
|
|
94
|
+
default:
|
|
95
|
+
throw new Error(`Unsupported zod type for tool parameter: ${zodType}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const BUCKETS = [
|
|
99
|
+
0, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000,
|
|
100
|
+
];
|
|
101
|
+
function bucketize(value) {
|
|
102
|
+
for (const bucket of BUCKETS) {
|
|
103
|
+
if (bucket >= value) {
|
|
104
|
+
return bucket;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return BUCKETS[BUCKETS.length - 1];
|
|
108
|
+
}
|
|
109
|
+
function transformValue(zodType, value) {
|
|
110
|
+
if (zodType === 'ZodString') {
|
|
111
|
+
return bucketize(value.length);
|
|
112
|
+
}
|
|
113
|
+
else if (zodType === 'ZodArray') {
|
|
114
|
+
return value.length;
|
|
115
|
+
}
|
|
116
|
+
else if (zodType === 'ZodRecord') {
|
|
117
|
+
return Object.keys(value).length;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function hasEquivalentType(zodType, value) {
|
|
124
|
+
if (zodType === 'ZodString') {
|
|
125
|
+
return typeof value === 'string';
|
|
126
|
+
}
|
|
127
|
+
else if (zodType === 'ZodArray') {
|
|
128
|
+
return Array.isArray(value);
|
|
129
|
+
}
|
|
130
|
+
else if (zodType === 'ZodNumber') {
|
|
131
|
+
return typeof value === 'number';
|
|
132
|
+
}
|
|
133
|
+
else if (zodType === 'ZodBoolean') {
|
|
134
|
+
return typeof value === 'boolean';
|
|
135
|
+
}
|
|
136
|
+
else if (zodType === 'ZodRecord') {
|
|
137
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
138
|
+
}
|
|
139
|
+
else if (zodType === 'ZodEnum') {
|
|
140
|
+
return (typeof value === 'string' ||
|
|
141
|
+
typeof value === 'number' ||
|
|
142
|
+
typeof value === 'boolean');
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export function sanitizeParams(params, schema) {
|
|
149
|
+
const transformed = {};
|
|
150
|
+
for (const [name, value] of Object.entries(params)) {
|
|
151
|
+
if (PARAM_BLOCKLIST.has(name)) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const zodType = getZodType(schema[name]);
|
|
155
|
+
if (!hasEquivalentType(zodType, value)) {
|
|
156
|
+
throw new Error(`parameter ${name} has type ${zodType} but value ${value} is not of equivalent type`);
|
|
157
|
+
}
|
|
158
|
+
const transformedName = transformArgName(zodType, name);
|
|
159
|
+
const transformedValue = transformValue(zodType, value);
|
|
160
|
+
transformed[transformedName] = transformedValue;
|
|
161
|
+
}
|
|
162
|
+
return transformed;
|
|
163
|
+
}
|
|
164
|
+
function transformDevToolsData(devToolsData) {
|
|
165
|
+
const logged = {};
|
|
166
|
+
if (devToolsData.cdpBackendNodeId !== undefined) {
|
|
167
|
+
logged.is_dom_element_selected = true;
|
|
168
|
+
}
|
|
169
|
+
if (devToolsData.cdpRequestId !== undefined) {
|
|
170
|
+
logged.is_network_request_selected = true;
|
|
171
|
+
}
|
|
172
|
+
return logged;
|
|
173
|
+
}
|
|
174
|
+
export function buildContext(devToolsData, pageUrl) {
|
|
175
|
+
let context;
|
|
176
|
+
if (devToolsData === undefined) {
|
|
177
|
+
context = { is_devtools_open: false };
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
context = {
|
|
181
|
+
is_devtools_open: Object.keys(devToolsData).length > 0,
|
|
182
|
+
};
|
|
183
|
+
const loggedDevtoolsData = transformDevToolsData(devToolsData);
|
|
184
|
+
if (Object.keys(loggedDevtoolsData).length > 0) {
|
|
185
|
+
context.devtools_data = loggedDevtoolsData;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (pageUrl !== undefined) {
|
|
189
|
+
context.is_localhost = isLocalhost(pageUrl);
|
|
190
|
+
}
|
|
191
|
+
return context;
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=transformation.js.map
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import crypto from 'node:crypto';
|
|
7
|
-
import { logger } from '../../logger.js';
|
|
7
|
+
import { logger } from '../../utils/logger.js';
|
|
8
8
|
const MAX_BUFFER_SIZE = 1000;
|
|
9
9
|
const DEFAULT_CLEARCUT_ENDPOINT = 'https://play.googleapis.com/log?format=json_proto';
|
|
10
10
|
const DEFAULT_FLUSH_INTERVAL_MS = 15 * 60 * 1000;
|
|
@@ -48,7 +48,7 @@ export class ClearcutSender {
|
|
|
48
48
|
app_version: this.#appVersion,
|
|
49
49
|
os_type: this.#osType,
|
|
50
50
|
};
|
|
51
|
-
logger('Enqueing telemetry event', JSON.stringify(eventToSend, null, 2));
|
|
51
|
+
logger?.('Enqueing telemetry event', JSON.stringify(eventToSend, null, 2));
|
|
52
52
|
this.#addToBuffer(eventToSend);
|
|
53
53
|
if (!this.#timerStarted) {
|
|
54
54
|
this.#timerStarted = true;
|
|
@@ -69,10 +69,10 @@ export class ClearcutSender {
|
|
|
69
69
|
this.#finalFlush(),
|
|
70
70
|
new Promise(resolve => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS)),
|
|
71
71
|
]);
|
|
72
|
-
logger('Final flush completed');
|
|
72
|
+
logger?.('Final flush completed');
|
|
73
73
|
}
|
|
74
74
|
catch (error) {
|
|
75
|
-
logger('Final flush failed:', error);
|
|
75
|
+
logger?.('Final flush failed:', error);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
async #flush() {
|
|
@@ -97,7 +97,7 @@ export class ClearcutSender {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
else if (result.isPermanentError) {
|
|
100
|
-
logger('Permanent error, dropped batch of', eventsToSend.length, 'events');
|
|
100
|
+
logger?.('Permanent error, dropped batch of', eventsToSend.length, 'events');
|
|
101
101
|
}
|
|
102
102
|
else {
|
|
103
103
|
// Transient error: Requeue events at the front of the buffer
|
|
@@ -108,7 +108,7 @@ export class ClearcutSender {
|
|
|
108
108
|
catch (error) {
|
|
109
109
|
// Safety catch for unexpected errors, requeue events
|
|
110
110
|
this.#buffer = [...eventsToSend, ...this.#buffer];
|
|
111
|
-
logger('Flush failed unexpectedly:', error);
|
|
111
|
+
logger?.('Flush failed unexpectedly:', error);
|
|
112
112
|
}
|
|
113
113
|
finally {
|
|
114
114
|
this.#isFlushing = false;
|
|
@@ -118,7 +118,7 @@ export class ClearcutSender {
|
|
|
118
118
|
#addToBuffer(event) {
|
|
119
119
|
if (this.#buffer.length >= MAX_BUFFER_SIZE) {
|
|
120
120
|
this.#buffer.shift();
|
|
121
|
-
logger('Telemetry buffer overflow: dropped oldest event');
|
|
121
|
+
logger?.('Telemetry buffer overflow: dropped oldest event');
|
|
122
122
|
}
|
|
123
123
|
this.#buffer.push({
|
|
124
124
|
event,
|
|
@@ -126,18 +126,18 @@ export class ClearcutSender {
|
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
128
|
#scheduleFlush(delayMs) {
|
|
129
|
-
logger(`Scheduling flush in ${delayMs}`);
|
|
129
|
+
logger?.(`Scheduling flush in ${delayMs}`);
|
|
130
130
|
if (this.#flushTimer) {
|
|
131
131
|
clearTimeout(this.#flushTimer);
|
|
132
132
|
}
|
|
133
133
|
this.#flushTimer = setTimeout(() => {
|
|
134
134
|
this.#flush().catch(err => {
|
|
135
|
-
logger('Flush error:', err);
|
|
135
|
+
logger?.('Flush error:', err);
|
|
136
136
|
});
|
|
137
137
|
}, delayMs);
|
|
138
138
|
}
|
|
139
139
|
async #sendBatch(events) {
|
|
140
|
-
logger(`Sending batch of ${events.length}`);
|
|
140
|
+
logger?.(`Sending batch of ${events.length}`);
|
|
141
141
|
const requestBody = {
|
|
142
142
|
log_source: LOG_SOURCE,
|
|
143
143
|
request_time_ms: Date.now().toString(),
|
|
@@ -176,7 +176,7 @@ export class ClearcutSender {
|
|
|
176
176
|
if (status >= 500 || status === 429) {
|
|
177
177
|
return { success: false };
|
|
178
178
|
}
|
|
179
|
-
logger('Telemetry permanent error:', status);
|
|
179
|
+
logger?.('Telemetry permanent error:', status);
|
|
180
180
|
return { success: false, isPermanentError: true };
|
|
181
181
|
}
|
|
182
182
|
catch {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import process from 'node:process';
|
|
7
7
|
import readline from 'node:readline';
|
|
8
8
|
import { parseArgs } from 'node:util';
|
|
9
|
-
import { logger, flushLogs, saveLogsToFile } from '../../logger.js';
|
|
9
|
+
import { logger, flushLogs, saveLogsToFile } from '../../utils/logger.js';
|
|
10
10
|
import { WatchdogMessageType } from '../types.js';
|
|
11
11
|
import { ClearcutSender } from './ClearcutSender.js';
|
|
12
12
|
function parseWatchdogArgs() {
|
|
@@ -65,7 +65,7 @@ function main() {
|
|
|
65
65
|
process.exit(code);
|
|
66
66
|
});
|
|
67
67
|
};
|
|
68
|
-
logger('Watchdog started', JSON.stringify({
|
|
68
|
+
logger?.('Watchdog started', JSON.stringify({
|
|
69
69
|
pid: process.pid,
|
|
70
70
|
parentPid,
|
|
71
71
|
version: appVersion,
|
|
@@ -84,15 +84,15 @@ function main() {
|
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
86
|
isShuttingDown = true;
|
|
87
|
-
logger(`Parent death detected (${reason}). Sending shutdown event...`);
|
|
87
|
+
logger?.(`Parent death detected (${reason}). Sending shutdown event...`);
|
|
88
88
|
sender
|
|
89
89
|
.sendShutdownEvent()
|
|
90
90
|
.then(() => {
|
|
91
|
-
logger('Shutdown event sent. Exiting.');
|
|
91
|
+
logger?.('Shutdown event sent. Exiting.');
|
|
92
92
|
exit(0);
|
|
93
93
|
})
|
|
94
94
|
.catch(err => {
|
|
95
|
-
logger('Failed to send shutdown event', err);
|
|
95
|
+
logger?.('Failed to send shutdown event', err);
|
|
96
96
|
exit(1);
|
|
97
97
|
});
|
|
98
98
|
}
|
|
@@ -114,7 +114,7 @@ function main() {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
catch (err) {
|
|
117
|
-
logger('Failed to parse IPC message', err);
|
|
117
|
+
logger?.('Failed to parse IPC message', err);
|
|
118
118
|
}
|
|
119
119
|
});
|
|
120
120
|
}
|