@oneuptime/common 14.0.9 → 14.0.10
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/Models/DatabaseModels/AutoRemediationSuggestion.ts +60 -0
- package/Models/DatabaseModels/CephCluster.ts +213 -0
- package/Models/DatabaseModels/DatabaseServer.ts +213 -0
- package/Models/DatabaseModels/DockerHost.ts +213 -0
- package/Models/DatabaseModels/DockerSwarmCluster.ts +213 -0
- package/Models/DatabaseModels/GlobalConfig.ts +1 -1
- package/Models/DatabaseModels/Host.ts +213 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/PodmanHost.ts +213 -0
- package/Models/DatabaseModels/ProxmoxCluster.ts +213 -0
- package/Models/DatabaseModels/ResourceAiAgent.ts +419 -0
- package/Models/DatabaseModels/RunnerJob.ts +144 -0
- package/Models/DatabaseModels/VMwareVCenter.ts +213 -0
- package/Server/API/AutoRemediationAPI.ts +392 -1
- package/Server/API/ResourceAiAccessAPI.ts +1669 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.ts +423 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Infrastructure/Semaphore.ts +22 -0
- package/Server/Middleware/TelemetryIngest.ts +15 -5
- package/Server/Services/AnalyticsDatabaseService.ts +45 -1
- package/Server/Services/AutoRemediationRuleEngineService.ts +940 -112
- package/Server/Services/CephClusterService.ts +109 -1
- package/Server/Services/DatabaseServerService.ts +116 -1
- package/Server/Services/DockerHostService.ts +109 -1
- package/Server/Services/DockerSwarmClusterService.ts +113 -1
- package/Server/Services/HostService.ts +126 -4
- package/Server/Services/MetricRecordingRuleService.ts +47 -0
- package/Server/Services/PodmanHostService.ts +109 -1
- package/Server/Services/ProxmoxClusterService.ts +110 -1
- package/Server/Services/ResourceAiAccessService.ts +1439 -0
- package/Server/Services/ResourceAiAgentJobService.ts +202 -0
- package/Server/Services/ResourceAiAgentService.ts +2432 -0
- package/Server/Services/RunnerJobService.ts +611 -4
- package/Server/Services/TelemetryUsageBillingService.ts +28 -0
- package/Server/Services/TraceRecordingRuleService.ts +33 -0
- package/Server/Services/VMwareVCenterService.ts +110 -1
- package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1434 -32
- package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +935 -21
- package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +25 -1
- package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +577 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAccessContext.ts +271 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.ts +45 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.ts +964 -0
- package/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.ts +333 -0
- package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +873 -0
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +72 -2
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +72 -5
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +72 -5
- package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +396 -13
- package/Server/Utils/AutoRemediation/RemediationVerifier.ts +35 -2
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +9 -1
- package/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.ts +920 -0
- package/Server/Utils/SessionReplay/SessionReplayUsage.ts +84 -6
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +35 -15
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +33 -15
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +21 -1
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +298 -224
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +35 -15
- package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +389 -175
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +366 -143
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.ts +163 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.ts +396 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.ts +418 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.ts +152 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.ts +251 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.ts +214 -0
- package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +93 -0
- package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +18 -6
- package/Tests/App/Dashboard/InvestigationInfrastructureTools.test.tsx +506 -0
- package/Tests/App/Dashboard/RemediationSuggestionCardDescription.test.tsx +209 -0
- package/Tests/App/Dashboard/RemediationSuggestionCardResource.test.tsx +317 -0
- package/Tests/App/Dashboard/ResourceAiAccessSettingsUtil.test.ts +921 -0
- package/Tests/App/Dashboard/ResourceAiAgentInstall.test.ts +860 -0
- package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +1721 -0
- package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +1002 -0
- package/Tests/App/Dashboard/ResourceAiInsightsPage.test.tsx +931 -0
- package/Tests/App/Dashboard/ResourceAiNavigation.test.tsx +575 -0
- package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +38 -7
- package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +33 -1
- package/Tests/Models/DatabaseModels/ResourceAiAccessColumns.test.ts +738 -0
- package/Tests/Models/DatabaseModels/ResourceAiAgentModel.test.ts +842 -0
- package/Tests/Server/API/AutoRemediationApproveResourceRound.test.ts +835 -0
- package/Tests/Server/API/ResourceAiAccessAPI.test.ts +2730 -0
- package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +60 -0
- package/Tests/Server/Infrastructure/Postgres/AddResourceAiAgentsMigration.test.ts +659 -0
- package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +31 -0
- package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +63 -5
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +103 -5
- package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +19 -1
- package/Tests/Server/Services/AutoRemediationResourceRuleEngine.test.ts +1279 -0
- package/Tests/Server/Services/DatabaseServerService.test.ts +55 -0
- package/Tests/Server/Services/GroupTelemetryUsageExcludeNames.test.ts +299 -0
- package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +44 -0
- package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +45 -6
- package/Tests/Server/Services/RecordingRuleReservedMetricName.test.ts +171 -0
- package/Tests/Server/Services/ResourceAiAccessChangeAuthorization.test.ts +256 -0
- package/Tests/Server/Services/ResourceAiAccessService.test.ts +1373 -0
- package/Tests/Server/Services/ResourceAiAgentJobService.test.ts +375 -0
- package/Tests/Server/Services/ResourceAiAgentServiceHelpers.test.ts +1114 -0
- package/Tests/Server/Services/ResourceAiAgentServiceLifecycle.test.ts +1050 -0
- package/Tests/Server/Services/ResourceAiAgentServiceRegister.test.ts +2251 -0
- package/Tests/Server/Services/ResourceAiSettingsCreate.test.ts +373 -0
- package/Tests/Server/Services/ResourceAiSettingsPermission.test.ts +1042 -0
- package/Tests/Server/Services/ResourceServiceDeleteCleansUpAi.test.ts +319 -0
- package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +105 -0
- package/Tests/Server/Services/RunnerJobEnqueueResourceCommand.test.ts +986 -0
- package/Tests/Server/Services/RunnerJobResourceCommandLane.test.ts +211 -0
- package/Tests/Server/Services/RunnerJobResourceCommandTimeoutAndRedaction.test.ts +352 -0
- package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +218 -0
- package/Tests/Server/TestingUtils/Services/FakeRunnerJobCount.ts +145 -0
- package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +453 -0
- package/Tests/Server/Utils/AI/InvestigationInfrastructureReport.test.ts +721 -0
- package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +94 -1
- package/Tests/Server/Utils/AI/RemediationCommandToolsResource.test.ts +1530 -0
- package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +1249 -0
- package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +117 -0
- package/Tests/Server/Utils/AI/RemediationResourceCopyParity.test.ts +463 -0
- package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +722 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceAccessContext.test.ts +266 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.test.ts +1220 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.test.ts +569 -0
- package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +830 -0
- package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorResource.test.ts +717 -0
- package/Tests/Server/Utils/AutoRemediation/RemediationVerifierResourceFollowUp.test.ts +338 -0
- package/Tests/Server/Utils/Monitor/Criteria/SessionReplayBudgetTemplateCriteria.test.ts +422 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.test.ts +1647 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +143 -1
- package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +33 -3
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsAccountNotLinked.test.ts +1093 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.test.ts +1049 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.test.ts +1676 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCards.test.ts +2884 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.test.ts +2490 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmit.test.ts +2293 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmitServerTimezone.test.ts +386 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.test.ts +1477 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.test.ts +1967 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsStripHtmlTags.test.ts +92 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsSubmittedFormRemoval.test.ts +1819 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.test.ts +1033 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezoneServerZone.test.ts +610 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsBotMessageHandling.test.ts +2610 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsCreateCommandsEndToEnd.test.ts +4672 -0
- package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +190 -65
- package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +10 -4
- package/Tests/Types/AutoRemediation/AiRemediationCommandPlanResourceCommand.test.ts +305 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +277 -13
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +113 -0
- package/Tests/Types/Monitor/RumAlertTemplates.test.ts +773 -2
- package/Tests/Types/ResourceAiAgent/AiResourceType.test.ts +419 -0
- package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +517 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +147 -8
- package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +769 -1
- package/Tests/Utils/AiRemediation/Resource/CephCommandPolicy.test.ts +1653 -0
- package/Tests/Utils/AiRemediation/Resource/CephOutputRedaction.test.ts +204 -0
- package/Tests/Utils/AiRemediation/Resource/DatabaseCommandPolicy.test.ts +1077 -0
- package/Tests/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.test.ts +558 -0
- package/Tests/Utils/AiRemediation/Resource/DatabaseQueryRedactor.test.ts +834 -0
- package/Tests/Utils/AiRemediation/Resource/DockerCliGrammar.test.ts +747 -0
- package/Tests/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.test.ts +1259 -0
- package/Tests/Utils/AiRemediation/Resource/DockerOutputRedaction.test.ts +386 -0
- package/Tests/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.test.ts +782 -0
- package/Tests/Utils/AiRemediation/Resource/GovcCommandPolicy.test.ts +2259 -0
- package/Tests/Utils/AiRemediation/Resource/HostCommandPolicy.test.ts +2019 -0
- package/Tests/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.test.ts +2497 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicy.test.ts +1305 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.test.ts +585 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactor.test.ts +334 -0
- package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactorCopyParity.test.ts +98 -0
- package/Tests/Utils/AiRemediation/Resource/ResourcePolicyImportClosure.test.ts +391 -0
- package/Tests/Utils/AiRemediation/ResourceAiAgentPolicyCopyParity.test.ts +497 -0
- package/Tests/Utils/SessionReplay/SessionReplayBudgetMetricType.test.ts +383 -0
- package/Types/AI/ResourceAiAccessApi.ts +140 -0
- package/Types/AI/ResourceAiAccessPermissions.ts +126 -0
- package/Types/AutoRemediation/AiRemediationCommandPlan.ts +183 -2
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +55 -22
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +35 -3
- package/Types/Monitor/RumAlertTemplates.ts +351 -4
- package/Types/ResourceAiAgent/AiResourceType.ts +310 -0
- package/Types/ResourceAiAgent/ResourceAiAccess.ts +574 -0
- package/Types/Rum/SessionReplayBudgetMetricType.ts +47 -0
- package/Types/Runbook/RunbookStepType.ts +29 -0
- package/Types/Telemetry/TelemetryIngestSurface.ts +14 -2
- package/Utils/AI/InvestigationReport.ts +121 -15
- package/Utils/AiRemediation/Resource/CephCommandPolicy.ts +1936 -0
- package/Utils/AiRemediation/Resource/DatabaseCommandPolicy.ts +166 -0
- package/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.ts +1532 -0
- package/Utils/AiRemediation/Resource/DatabaseQueryRedactor.ts +1394 -0
- package/Utils/AiRemediation/Resource/DockerCliGrammar.ts +1839 -0
- package/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.ts +490 -0
- package/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.ts +687 -0
- package/Utils/AiRemediation/Resource/GovcCommandPolicy.ts +2096 -0
- package/Utils/AiRemediation/Resource/HostCommandPolicy.ts +2982 -0
- package/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.ts +1679 -0
- package/Utils/AiRemediation/Resource/ResourceCommandPolicy.ts +851 -0
- package/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.ts +593 -0
- package/Utils/AiRemediation/Resource/ResourceOutputRedactor.ts +2812 -0
- package/Utils/SessionReplay/SessionReplayBudgetMetricType.ts +184 -0
- package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
- package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CephCluster.js +219 -0
- package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseServer.js +219 -0
- package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +219 -0
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +219 -0
- package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Host.js +219 -0
- package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/PodmanHost.js +219 -0
- package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +219 -0
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ResourceAiAgent.js +439 -0
- package/build/dist/Models/DatabaseModels/ResourceAiAgent.js.map +1 -0
- package/build/dist/Models/DatabaseModels/RunnerJob.js +145 -0
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js +219 -0
- package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
- package/build/dist/Server/API/AutoRemediationAPI.js +231 -1
- package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
- package/build/dist/Server/API/ResourceAiAccessAPI.js +1119 -0
- package/build/dist/Server/API/ResourceAiAccessAPI.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js +168 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +6 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +12 -5
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +26 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +601 -3
- package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterService.js +104 -0
- package/build/dist/Server/Services/CephClusterService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseServerService.js +99 -0
- package/build/dist/Server/Services/DatabaseServerService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +104 -0
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterService.js +104 -0
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +114 -2
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/MetricRecordingRuleService.js +46 -0
- package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostService.js +104 -0
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterService.js +104 -0
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
- package/build/dist/Server/Services/ResourceAiAccessService.js +1028 -0
- package/build/dist/Server/Services/ResourceAiAccessService.js.map +1 -0
- package/build/dist/Server/Services/ResourceAiAgentJobService.js +173 -0
- package/build/dist/Server/Services/ResourceAiAgentJobService.js.map +1 -0
- package/build/dist/Server/Services/ResourceAiAgentService.js +1687 -0
- package/build/dist/Server/Services/ResourceAiAgentService.js.map +1 -0
- package/build/dist/Server/Services/RunnerJobService.js +344 -5
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +26 -0
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/TraceRecordingRuleService.js +37 -0
- package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -1
- package/build/dist/Server/Services/VMwareVCenterService.js +104 -0
- package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1029 -30
- package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +633 -28
- package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +21 -1
- package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +330 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js +160 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js +33 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js +640 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js +226 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js.map +1 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +600 -0
- package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +50 -4
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +55 -4
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +55 -4
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +290 -13
- package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +29 -1
- package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +9 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js +627 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js.map +1 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js +60 -5
- package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +19 -15
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +19 -15
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +17 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +183 -209
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +19 -15
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +233 -167
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +263 -110
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js +129 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js +266 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js +258 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js +104 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js +183 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js +123 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js.map +1 -0
- package/build/dist/Types/AI/ResourceAiAccessApi.js +30 -0
- package/build/dist/Types/AI/ResourceAiAccessApi.js.map +1 -0
- package/build/dist/Types/AI/ResourceAiAccessPermissions.js +98 -0
- package/build/dist/Types/AI/ResourceAiAccessPermissions.js.map +1 -0
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +116 -29
- package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +47 -21
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +5 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/RumAlertTemplates.js +199 -3
- package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
- package/build/dist/Types/ResourceAiAgent/AiResourceType.js +242 -0
- package/build/dist/Types/ResourceAiAgent/AiResourceType.js.map +1 -0
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +275 -0
- package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -0
- package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js +45 -0
- package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js +27 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +13 -2
- package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
- package/build/dist/Utils/AI/InvestigationReport.js +71 -11
- package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
- package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js +1462 -0
- package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js +122 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js +1139 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js +1060 -0
- package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js +1301 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js +370 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js +498 -0
- package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js +1565 -0
- package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js +2206 -0
- package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js +1129 -0
- package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js +565 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js +408 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js.map +1 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js +1910 -0
- package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js.map +1 -0
- package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js +160 -0
- package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RumAlertTemplate,
|
|
3
3
|
RumAlertTemplateArgs,
|
|
4
|
+
RumAlertTemplateContext,
|
|
5
|
+
RumAlertTemplateRequirement,
|
|
4
6
|
getAllRumAlertTemplates,
|
|
5
7
|
getRumAlertTemplateById,
|
|
8
|
+
getRumAlertTemplates,
|
|
6
9
|
} from "../../../Types/Monitor/RumAlertTemplates";
|
|
7
10
|
import MonitorStep from "../../../Types/Monitor/MonitorStep";
|
|
8
11
|
import MonitorType from "../../../Types/Monitor/MonitorType";
|
|
@@ -15,7 +18,10 @@ import {
|
|
|
15
18
|
} from "../../../Types/Monitor/CriteriaFilter";
|
|
16
19
|
import MetricsAggregationType from "../../../Types/Metrics/MetricsAggregationType";
|
|
17
20
|
import RollingTime from "../../../Types/RollingTime/RollingTime";
|
|
21
|
+
import RollingTimeUtil from "../../../Types/RollingTime/RollingTimeUtil";
|
|
22
|
+
import InBetween from "../../../Types/BaseDatabase/InBetween";
|
|
18
23
|
import ObjectID from "../../../Types/ObjectID";
|
|
24
|
+
import { JSONObject } from "../../../Types/JSON";
|
|
19
25
|
import { SpanStatus } from "../../../Models/AnalyticsModels/Span";
|
|
20
26
|
import MonitorStepMetricMonitor from "../../../Types/Monitor/MonitorStepMetricMonitor";
|
|
21
27
|
import MetricQueryConfigData from "../../../Types/Metrics/MetricQueryConfigData";
|
|
@@ -25,6 +31,10 @@ import {
|
|
|
25
31
|
ServiceAlertTemplate,
|
|
26
32
|
getAllServiceAlertTemplates,
|
|
27
33
|
} from "../../../Types/Monitor/ServiceAlertTemplates";
|
|
34
|
+
import SessionReplayBudgetMetricType from "../../../Types/Rum/SessionReplayBudgetMetricType";
|
|
35
|
+
import SessionReplayBudgetMetricTypeUtil, {
|
|
36
|
+
SESSION_REPLAY_BUDGET_METRIC_INTERVAL_MINUTES,
|
|
37
|
+
} from "../../../Utils/SessionReplay/SessionReplayBudgetMetricType";
|
|
28
38
|
|
|
29
39
|
const RUM_APPLICATION_ID: ObjectID = ObjectID.generate();
|
|
30
40
|
|
|
@@ -136,8 +146,165 @@ const SEVERITY_CASES: Array<{
|
|
|
136
146
|
category: "Errors",
|
|
137
147
|
severity: "Critical",
|
|
138
148
|
},
|
|
149
|
+
/*
|
|
150
|
+
* "Nearly spent" warns while there is still time to act; "spent" means the
|
|
151
|
+
* recorders have already been told to stop, so nothing more is recorded.
|
|
152
|
+
*/
|
|
153
|
+
{
|
|
154
|
+
id: "rum-session-replay-daily-budget-nearly-spent",
|
|
155
|
+
category: "Session Replay",
|
|
156
|
+
severity: "Warning",
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "rum-session-replay-daily-budget-spent",
|
|
160
|
+
category: "Session Replay",
|
|
161
|
+
severity: "Critical",
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
id: "rum-session-replay-monthly-budget-nearly-spent",
|
|
165
|
+
category: "Session Replay",
|
|
166
|
+
severity: "Warning",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "rum-session-replay-monthly-budget-spent",
|
|
170
|
+
category: "Session Replay",
|
|
171
|
+
severity: "Critical",
|
|
172
|
+
},
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
/*
|
|
176
|
+
* The four session replay storage budget templates, restated from the spec
|
|
177
|
+
* rather than read back from the module, so a change to either has to be made
|
|
178
|
+
* twice. The alias is shared within a pair on purpose (same series, two
|
|
179
|
+
* thresholds); the pairs read different series.
|
|
180
|
+
*/
|
|
181
|
+
interface BudgetCase {
|
|
182
|
+
id: string;
|
|
183
|
+
name: string;
|
|
184
|
+
metricName: SessionReplayBudgetMetricType;
|
|
185
|
+
metricAlias: string;
|
|
186
|
+
threshold: number;
|
|
187
|
+
breachName: string;
|
|
188
|
+
requirement: RumAlertTemplateRequirement;
|
|
189
|
+
incidentTitle: string;
|
|
190
|
+
isProjectScoped: boolean;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const BUDGET_CASES: Array<BudgetCase> = [
|
|
194
|
+
{
|
|
195
|
+
id: "rum-session-replay-daily-budget-nearly-spent",
|
|
196
|
+
name: "Session Replay Daily Budget Nearly Spent",
|
|
197
|
+
metricName: SessionReplayBudgetMetricType.ProjectDailyUsedPercent,
|
|
198
|
+
metricAlias: "rum_replay_daily_budget_used",
|
|
199
|
+
threshold: 80,
|
|
200
|
+
breachName: "Session Replay Daily Budget Nearly Spent - 80% or more used",
|
|
201
|
+
requirement: "SessionReplayRecording",
|
|
202
|
+
incidentTitle:
|
|
203
|
+
"[RUM] Project's daily session replay budget nearly spent - Storefront",
|
|
204
|
+
isProjectScoped: true,
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
id: "rum-session-replay-daily-budget-spent",
|
|
208
|
+
name: "Session Replay Daily Budget Spent",
|
|
209
|
+
metricName: SessionReplayBudgetMetricType.ProjectDailyUsedPercent,
|
|
210
|
+
metricAlias: "rum_replay_daily_budget_used",
|
|
211
|
+
threshold: 100,
|
|
212
|
+
breachName: "Session Replay Daily Budget Spent - 100% used",
|
|
213
|
+
requirement: "SessionReplayRecording",
|
|
214
|
+
incidentTitle:
|
|
215
|
+
"[RUM] Session replay paused: project's daily budget spent - Storefront",
|
|
216
|
+
isProjectScoped: true,
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: "rum-session-replay-monthly-budget-nearly-spent",
|
|
220
|
+
name: "Session Replay Monthly Budget Nearly Spent",
|
|
221
|
+
metricName: SessionReplayBudgetMetricType.ApplicationMonthlyUsedPercent,
|
|
222
|
+
metricAlias: "rum_replay_monthly_budget_used",
|
|
223
|
+
threshold: 80,
|
|
224
|
+
breachName: "Session Replay Monthly Budget Nearly Spent - 80% or more used",
|
|
225
|
+
requirement: "SessionReplayMonthlyBudget",
|
|
226
|
+
incidentTitle:
|
|
227
|
+
"[RUM] Monthly session replay budget nearly spent - Storefront",
|
|
228
|
+
isProjectScoped: false,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: "rum-session-replay-monthly-budget-spent",
|
|
232
|
+
name: "Session Replay Monthly Budget Spent",
|
|
233
|
+
metricName: SessionReplayBudgetMetricType.ApplicationMonthlyUsedPercent,
|
|
234
|
+
metricAlias: "rum_replay_monthly_budget_used",
|
|
235
|
+
threshold: 100,
|
|
236
|
+
breachName: "Session Replay Monthly Budget Spent - 100% used",
|
|
237
|
+
requirement: "SessionReplayMonthlyBudget",
|
|
238
|
+
incidentTitle:
|
|
239
|
+
"[RUM] Session replay paused: monthly budget spent - Storefront",
|
|
240
|
+
isProjectScoped: false,
|
|
241
|
+
},
|
|
242
|
+
];
|
|
243
|
+
|
|
244
|
+
const BUDGET_TEMPLATE_IDS: Array<string> = BUDGET_CASES.map(
|
|
245
|
+
(item: BudgetCase) => {
|
|
246
|
+
return item.id;
|
|
247
|
+
},
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
// The seven templates every RUM application was offered before the budgets.
|
|
251
|
+
const CORE_TEMPLATE_IDS: Array<string> = [
|
|
252
|
+
"rum-poor-lcp",
|
|
253
|
+
"rum-poor-inp",
|
|
254
|
+
"rum-poor-cls",
|
|
255
|
+
"rum-slow-fcp",
|
|
256
|
+
"rum-slow-ttfb",
|
|
257
|
+
"rum-failed-user-operations",
|
|
258
|
+
"rum-unhandled-exceptions",
|
|
259
|
+
];
|
|
260
|
+
|
|
261
|
+
const DAILY_TEMPLATE_IDS: Array<string> = [
|
|
262
|
+
"rum-session-replay-daily-budget-nearly-spent",
|
|
263
|
+
"rum-session-replay-daily-budget-spent",
|
|
139
264
|
];
|
|
140
265
|
|
|
266
|
+
const MONTHLY_TEMPLATE_IDS: Array<string> = [
|
|
267
|
+
"rum-session-replay-monthly-budget-nearly-spent",
|
|
268
|
+
"rum-session-replay-monthly-budget-spent",
|
|
269
|
+
];
|
|
270
|
+
|
|
271
|
+
// An application that records replays and has a monthly budget of 10 GiB.
|
|
272
|
+
const FULL_CONTEXT: RumAlertTemplateContext = {
|
|
273
|
+
sessionReplayEnabled: true,
|
|
274
|
+
sessionReplayHasRecorded: true,
|
|
275
|
+
sessionReplayMonthlyBudgetInGB: 10,
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
function offeredIds(
|
|
279
|
+
context?: RumAlertTemplateContext | undefined,
|
|
280
|
+
): Array<string> {
|
|
281
|
+
return getRumAlertTemplates(context).map((template: RumAlertTemplate) => {
|
|
282
|
+
return template.id;
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// The first filter of the breach criteria and of the Healthy one.
|
|
287
|
+
interface BudgetFilters {
|
|
288
|
+
breach: CriteriaFilter | undefined;
|
|
289
|
+
recovery: CriteriaFilter | undefined;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function getFilters(step: MonitorStep): BudgetFilters {
|
|
293
|
+
const [breach, recovery]: Array<MonitorCriteriaInstance> = getCriteria(step);
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
breach: breach?.data?.filters[0],
|
|
297
|
+
recovery: recovery?.data?.filters[0],
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function getWindowInMinutes(rollingTime: RollingTime): number {
|
|
302
|
+
const window: InBetween<Date> =
|
|
303
|
+
RollingTimeUtil.convertToStartAndEndDate(rollingTime);
|
|
304
|
+
|
|
305
|
+
return (window.endValue.getTime() - window.startValue.getTime()) / 60000;
|
|
306
|
+
}
|
|
307
|
+
|
|
141
308
|
/*
|
|
142
309
|
* The community spellings `WEB_VITAL_DEFS` in telemetryMetrics.ts probes for,
|
|
143
310
|
* copied verbatim. The overview card tries all four and keeps whichever has
|
|
@@ -180,7 +347,7 @@ describe("RumAlertTemplates", () => {
|
|
|
180
347
|
return template.id;
|
|
181
348
|
});
|
|
182
349
|
|
|
183
|
-
expect(templates).toHaveLength(
|
|
350
|
+
expect(templates).toHaveLength(11);
|
|
184
351
|
expect(new Set(ids).size).toBe(ids.length);
|
|
185
352
|
expect(ids).toEqual([
|
|
186
353
|
...WEB_VITAL_CASES.map((item: WebVitalCase) => {
|
|
@@ -188,6 +355,10 @@ describe("RumAlertTemplates", () => {
|
|
|
188
355
|
}),
|
|
189
356
|
"rum-failed-user-operations",
|
|
190
357
|
"rum-unhandled-exceptions",
|
|
358
|
+
"rum-session-replay-daily-budget-nearly-spent",
|
|
359
|
+
"rum-session-replay-daily-budget-spent",
|
|
360
|
+
"rum-session-replay-monthly-budget-nearly-spent",
|
|
361
|
+
"rum-session-replay-monthly-budget-spent",
|
|
191
362
|
]);
|
|
192
363
|
});
|
|
193
364
|
|
|
@@ -195,7 +366,7 @@ describe("RumAlertTemplates", () => {
|
|
|
195
366
|
const first: Array<RumAlertTemplate> = getAllRumAlertTemplates();
|
|
196
367
|
first.pop();
|
|
197
368
|
|
|
198
|
-
expect(getAllRumAlertTemplates()).toHaveLength(
|
|
369
|
+
expect(getAllRumAlertTemplates()).toHaveLength(11);
|
|
199
370
|
});
|
|
200
371
|
|
|
201
372
|
test("returns undefined for an unknown template id", () => {
|
|
@@ -257,6 +428,25 @@ describe("RumAlertTemplates", () => {
|
|
|
257
428
|
);
|
|
258
429
|
expect(healthyFilter?.filterType).toBe(FilterType.LessThan);
|
|
259
430
|
expect(healthyFilter?.value).toBe(item.threshold);
|
|
431
|
+
|
|
432
|
+
/*
|
|
433
|
+
* The recovery reduces the window exactly as the breach does. The
|
|
434
|
+
* budget templates made the reduction a parameter; the web vitals
|
|
435
|
+
* must keep evaluating the five-minute Average on both sides.
|
|
436
|
+
*/
|
|
437
|
+
expect(healthyFilter?.metricMonitorOptions?.metricAlias).toBe(
|
|
438
|
+
item.metricAlias,
|
|
439
|
+
);
|
|
440
|
+
expect(healthyFilter?.metricMonitorOptions?.metricAggregationType).toBe(
|
|
441
|
+
EvaluateOverTimeType.Average,
|
|
442
|
+
);
|
|
443
|
+
expect(healthyFilter?.metricMonitorOptions?.thresholdUnit).toBe(
|
|
444
|
+
item.unit,
|
|
445
|
+
);
|
|
446
|
+
expect(healthy?.data?.description).toBe(
|
|
447
|
+
"The RUM signal for Storefront is within its recommended threshold.",
|
|
448
|
+
);
|
|
449
|
+
expect(template.requirement).toBeUndefined();
|
|
260
450
|
},
|
|
261
451
|
);
|
|
262
452
|
|
|
@@ -419,3 +609,584 @@ describe("RumAlertTemplates", () => {
|
|
|
419
609
|
).toBe(RUM_APPLICATION_ID.toString());
|
|
420
610
|
});
|
|
421
611
|
});
|
|
612
|
+
|
|
613
|
+
/*
|
|
614
|
+
* The session replay storage budget templates. Each one is a Metrics monitor
|
|
615
|
+
* over a series the budget sweep posts every five minutes under the RUM
|
|
616
|
+
* application's id, and every shape assertion below is one a mistake in would
|
|
617
|
+
* produce a monitor that looks right on the page and never fires, fires late,
|
|
618
|
+
* or never resolves:
|
|
619
|
+
*
|
|
620
|
+
* - scope: without `telemetryServiceIds` the query reads every application
|
|
621
|
+
* in the project, and the recommendation fingerprint loses its resource;
|
|
622
|
+
* - the reduction: without `metricAlias` no metricMonitorOptions are
|
|
623
|
+
* written and the window silently falls back to All Values, which only
|
|
624
|
+
* fires once EVERY point crossed;
|
|
625
|
+
* - the unit: "%" on the alias, the threshold and the catalog alike, or the
|
|
626
|
+
* evaluator converts the value it compares.
|
|
627
|
+
*/
|
|
628
|
+
describe("RumAlertTemplates - session replay storage budget", () => {
|
|
629
|
+
test.each(BUDGET_CASES)(
|
|
630
|
+
"$id watches $metricName for this application alone, at its threshold",
|
|
631
|
+
(item: BudgetCase) => {
|
|
632
|
+
const template: RumAlertTemplate = getTemplate(item.id);
|
|
633
|
+
const step: MonitorStep = template.getMonitorStep(buildArgs());
|
|
634
|
+
const metricMonitor: MonitorStepMetricMonitor | undefined =
|
|
635
|
+
step.data?.metricMonitor;
|
|
636
|
+
|
|
637
|
+
expect(template.name).toBe(item.name);
|
|
638
|
+
expect(template.monitorType).toBe(MonitorType.Metrics);
|
|
639
|
+
expect(template.category).toBe("Session Replay");
|
|
640
|
+
expect(template.requirement).toBe(item.requirement);
|
|
641
|
+
|
|
642
|
+
expect(metricMonitor).toBeDefined();
|
|
643
|
+
expect(metricMonitor?.rollingTime).toBe(RollingTime.Past15Minutes);
|
|
644
|
+
expect(
|
|
645
|
+
metricMonitor?.telemetryServiceIds?.map((id: ObjectID) => {
|
|
646
|
+
return id.toString();
|
|
647
|
+
}),
|
|
648
|
+
).toEqual([RUM_APPLICATION_ID.toString()]);
|
|
649
|
+
|
|
650
|
+
expect(metricMonitor?.metricViewConfig.queryConfigs).toHaveLength(1);
|
|
651
|
+
expect(metricMonitor?.metricViewConfig.formulaConfigs).toEqual([]);
|
|
652
|
+
|
|
653
|
+
const query: MetricQueryConfigData | undefined =
|
|
654
|
+
metricMonitor?.metricViewConfig.queryConfigs[0];
|
|
655
|
+
|
|
656
|
+
expect(query?.metricQueryData.filterData.metricName).toBe(
|
|
657
|
+
item.metricName,
|
|
658
|
+
);
|
|
659
|
+
expect(query?.metricQueryData.filterData.aggegationType).toBe(
|
|
660
|
+
MetricsAggregationType.Max,
|
|
661
|
+
);
|
|
662
|
+
// Scoped by primaryEntityId alone: no attribute filter, no grouping.
|
|
663
|
+
expect(query?.metricQueryData.filterData.attributes).toEqual({});
|
|
664
|
+
expect(query?.metricQueryData.groupBy).toBeUndefined();
|
|
665
|
+
expect(MonitorStep.getGroupByAttributeKeys(step)).toEqual([]);
|
|
666
|
+
expect(query?.metricAliasData?.metricVariable).toBe(item.metricAlias);
|
|
667
|
+
expect(query?.metricAliasData?.legendUnit).toBe("%");
|
|
668
|
+
expect(query?.metricAliasData?.title).toBe(item.name);
|
|
669
|
+
expect(query?.metricAliasData?.legend).toBe(item.name);
|
|
670
|
+
|
|
671
|
+
const { breach, recovery }: BudgetFilters = getFilters(step);
|
|
672
|
+
|
|
673
|
+
expect(getCriteria(step)).toHaveLength(2);
|
|
674
|
+
|
|
675
|
+
expect(breach?.checkOn).toBe(CheckOn.MetricValue);
|
|
676
|
+
expect(breach?.filterType).toBe(FilterType.GreaterThanOrEqualTo);
|
|
677
|
+
expect(breach?.value).toBe(item.threshold);
|
|
678
|
+
|
|
679
|
+
expect(recovery?.checkOn).toBe(CheckOn.MetricValue);
|
|
680
|
+
expect(recovery?.filterType).toBe(FilterType.LessThan);
|
|
681
|
+
expect(recovery?.value).toBe(item.threshold);
|
|
682
|
+
|
|
683
|
+
for (const filter of [breach, recovery]) {
|
|
684
|
+
expect(filter?.metricMonitorOptions).toEqual({
|
|
685
|
+
metricAggregationType: EvaluateOverTimeType.MaximumValue,
|
|
686
|
+
metricAlias: item.metricAlias,
|
|
687
|
+
thresholdUnit: "%",
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
);
|
|
692
|
+
|
|
693
|
+
test.each(BUDGET_CASES)(
|
|
694
|
+
"$id names its criteria and titles its incidents and alerts",
|
|
695
|
+
(item: BudgetCase) => {
|
|
696
|
+
const step: MonitorStep = getTemplate(item.id).getMonitorStep(
|
|
697
|
+
buildArgs(),
|
|
698
|
+
);
|
|
699
|
+
const [breach, recovery]: Array<MonitorCriteriaInstance> =
|
|
700
|
+
getCriteria(step);
|
|
701
|
+
|
|
702
|
+
expect(breach?.data?.name).toBe(item.breachName);
|
|
703
|
+
expect(breach?.data?.description).toMatch(/^Triggers when /);
|
|
704
|
+
expect(breach?.data?.description).toContain(`${item.threshold}%`);
|
|
705
|
+
expect(breach?.data?.description).toMatch(
|
|
706
|
+
/ at any point in the last 15 minutes\.$/,
|
|
707
|
+
);
|
|
708
|
+
|
|
709
|
+
expect(recovery?.data?.name).toBe("Healthy");
|
|
710
|
+
expect(recovery?.data?.description).toBe(
|
|
711
|
+
"Session replay budget use for Storefront is below the alert threshold.",
|
|
712
|
+
);
|
|
713
|
+
|
|
714
|
+
expect(breach?.data?.incidents[0]?.title).toBe(item.incidentTitle);
|
|
715
|
+
expect(breach?.data?.alerts[0]?.title).toBe(item.incidentTitle);
|
|
716
|
+
expect(breach?.data?.incidents[0]?.description).toBe(
|
|
717
|
+
breach?.data?.alerts[0]?.description,
|
|
718
|
+
);
|
|
719
|
+
expect(breach?.data?.incidents[0]?.autoResolveIncident).toBe(true);
|
|
720
|
+
expect(breach?.data?.alerts[0]?.autoResolveAlert).toBe(true);
|
|
721
|
+
|
|
722
|
+
// Both criteria move the monitor's status, so a recovery resolves.
|
|
723
|
+
expect(breach?.data?.changeMonitorStatus).toBe(true);
|
|
724
|
+
expect(recovery?.data?.changeMonitorStatus).toBe(true);
|
|
725
|
+
},
|
|
726
|
+
);
|
|
727
|
+
|
|
728
|
+
/*
|
|
729
|
+
* The enum and its util are the contract the sweep writes by. A template
|
|
730
|
+
* that reads the series in another unit gets its values converted before
|
|
731
|
+
* they are compared; one aggregated differently from how the catalog
|
|
732
|
+
* charts it reads a different number from the one on screen.
|
|
733
|
+
*/
|
|
734
|
+
test.each(BUDGET_CASES)(
|
|
735
|
+
"$id reads the series in the unit the metric catalog registers and the aggregation it names",
|
|
736
|
+
(item: BudgetCase) => {
|
|
737
|
+
const step: MonitorStep = getTemplate(item.id).getMonitorStep(
|
|
738
|
+
buildArgs(),
|
|
739
|
+
);
|
|
740
|
+
const query: MetricQueryConfigData | undefined =
|
|
741
|
+
step.data?.metricMonitor?.metricViewConfig.queryConfigs[0];
|
|
742
|
+
const { breach }: BudgetFilters = getFilters(step);
|
|
743
|
+
|
|
744
|
+
expect(SessionReplayBudgetMetricTypeUtil.getAll()).toContain(
|
|
745
|
+
item.metricName,
|
|
746
|
+
);
|
|
747
|
+
expect(
|
|
748
|
+
SessionReplayBudgetMetricTypeUtil.isReservedMetricName(item.metricName),
|
|
749
|
+
).toBe(true);
|
|
750
|
+
expect(query?.metricAliasData?.legendUnit).toBe(
|
|
751
|
+
SessionReplayBudgetMetricTypeUtil.getUnit(item.metricName),
|
|
752
|
+
);
|
|
753
|
+
expect(breach?.metricMonitorOptions?.thresholdUnit).toBe(
|
|
754
|
+
SessionReplayBudgetMetricTypeUtil.getUnit(item.metricName),
|
|
755
|
+
);
|
|
756
|
+
expect(query?.metricQueryData.filterData.aggegationType).toBe(
|
|
757
|
+
SessionReplayBudgetMetricTypeUtil.getAggregationType(item.metricName),
|
|
758
|
+
);
|
|
759
|
+
expect(
|
|
760
|
+
SessionReplayBudgetMetricTypeUtil.isProjectScoped(item.metricName),
|
|
761
|
+
).toBe(item.isProjectScoped);
|
|
762
|
+
},
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
/*
|
|
766
|
+
* The budgets are GiB while every byte threshold and chart is decimal, so a
|
|
767
|
+
* bytes template would fire at 93% of a 1 GiB limit and call it spent.
|
|
768
|
+
*/
|
|
769
|
+
test("alerts on the percent series, never on bytes", () => {
|
|
770
|
+
for (const id of BUDGET_TEMPLATE_IDS) {
|
|
771
|
+
const metricName: unknown =
|
|
772
|
+
getTemplate(id).getMonitorStep(buildArgs()).data?.metricMonitor
|
|
773
|
+
?.metricViewConfig.queryConfigs[0]?.metricQueryData.filterData
|
|
774
|
+
.metricName;
|
|
775
|
+
|
|
776
|
+
expect(typeof metricName).toBe("string");
|
|
777
|
+
expect(metricName).not.toBe(
|
|
778
|
+
SessionReplayBudgetMetricType.ProjectDailyUsedBytes,
|
|
779
|
+
);
|
|
780
|
+
expect(metricName).not.toBe(
|
|
781
|
+
SessionReplayBudgetMetricType.ApplicationMonthlyUsedBytes,
|
|
782
|
+
);
|
|
783
|
+
expect(String(metricName).endsWith(".percent")).toBe(true);
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
/*
|
|
788
|
+
* An empty window meets no criteria and resolves an open alert, so the
|
|
789
|
+
* window has to hold more than one of the sweep's points - one late sweep
|
|
790
|
+
* must not resolve a budget that is still spent.
|
|
791
|
+
*/
|
|
792
|
+
test("looks back far enough to hold three of the sweep's points", () => {
|
|
793
|
+
expect(getWindowInMinutes(RollingTime.Past15Minutes)).toBe(15);
|
|
794
|
+
|
|
795
|
+
for (const id of BUDGET_TEMPLATE_IDS) {
|
|
796
|
+
const rollingTime: RollingTime | undefined =
|
|
797
|
+
getTemplate(id).getMonitorStep(buildArgs()).data?.metricMonitor
|
|
798
|
+
?.rollingTime;
|
|
799
|
+
|
|
800
|
+
expect(rollingTime).toBeDefined();
|
|
801
|
+
expect(getWindowInMinutes(rollingTime!)).toBeGreaterThanOrEqual(
|
|
802
|
+
3 * SESSION_REPLAY_BUDGET_METRIC_INTERVAL_MINUTES,
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
test("each pair reads one series under one alias, and the two pairs read different ones", () => {
|
|
808
|
+
const seriesOf: (id: string) => string = (id: string): string => {
|
|
809
|
+
const query: MetricQueryConfigData | undefined =
|
|
810
|
+
getTemplate(id).getMonitorStep(buildArgs()).data?.metricMonitor
|
|
811
|
+
?.metricViewConfig.queryConfigs[0];
|
|
812
|
+
|
|
813
|
+
return `${query?.metricQueryData.filterData.metricName} as ${query?.metricAliasData?.metricVariable}`;
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
expect(seriesOf(DAILY_TEMPLATE_IDS[0]!)).toBe(
|
|
817
|
+
seriesOf(DAILY_TEMPLATE_IDS[1]!),
|
|
818
|
+
);
|
|
819
|
+
expect(seriesOf(MONTHLY_TEMPLATE_IDS[0]!)).toBe(
|
|
820
|
+
seriesOf(MONTHLY_TEMPLATE_IDS[1]!),
|
|
821
|
+
);
|
|
822
|
+
expect(seriesOf(DAILY_TEMPLATE_IDS[0]!)).not.toBe(
|
|
823
|
+
seriesOf(MONTHLY_TEMPLATE_IDS[0]!),
|
|
824
|
+
);
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
/*
|
|
828
|
+
* The card clamps at three lines, so the sentence that decides whether to
|
|
829
|
+
* click create comes first - and the daily cards have to say the limit is
|
|
830
|
+
* the project's, or every application gets its own copy of the monitor.
|
|
831
|
+
*/
|
|
832
|
+
test("cards lead with what they alert on, and the daily ones say one monitor covers the project", () => {
|
|
833
|
+
for (const id of BUDGET_TEMPLATE_IDS) {
|
|
834
|
+
expect(getTemplate(id).description).toMatch(/^Alert when /);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
for (const id of DAILY_TEMPLATE_IDS) {
|
|
838
|
+
const description: string = getTemplate(id).description;
|
|
839
|
+
|
|
840
|
+
expect(description).toContain("the project's");
|
|
841
|
+
expect(description).toContain(
|
|
842
|
+
"shared by every application in the project",
|
|
843
|
+
);
|
|
844
|
+
expect(description).toContain("one of these monitors covers them all");
|
|
845
|
+
expect(description).toContain("00:00 UTC");
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
for (const id of MONTHLY_TEMPLATE_IDS) {
|
|
849
|
+
const description: string = getTemplate(id).description;
|
|
850
|
+
|
|
851
|
+
expect(description).toContain("this application's");
|
|
852
|
+
expect(description).toContain("(UTC)");
|
|
853
|
+
expect(description).not.toContain("shared by every application");
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
/*
|
|
858
|
+
* What the incident and the alert say, verbatim. Every lever named is one
|
|
859
|
+
* the ingest path refuses BEFORE it charges a byte (allowed origins,
|
|
860
|
+
* sampling, the upload trigger), and the daily limit is only ever raised by
|
|
861
|
+
* the deployment - so the text never sends anyone to a setting that cannot
|
|
862
|
+
* help.
|
|
863
|
+
*/
|
|
864
|
+
test("incident and alert descriptions name the levers that act before bytes are charged", () => {
|
|
865
|
+
const descriptionOf: (id: string, monitorName: string) => string = (
|
|
866
|
+
id: string,
|
|
867
|
+
monitorName: string,
|
|
868
|
+
): string => {
|
|
869
|
+
const [breach]: Array<MonitorCriteriaInstance> = getCriteria(
|
|
870
|
+
getTemplate(id).getMonitorStep({
|
|
871
|
+
...buildArgs(),
|
|
872
|
+
monitorName: monitorName,
|
|
873
|
+
}),
|
|
874
|
+
);
|
|
875
|
+
|
|
876
|
+
expect(breach?.data?.alerts[0]?.description).toBe(
|
|
877
|
+
breach?.data?.incidents[0]?.description,
|
|
878
|
+
);
|
|
879
|
+
|
|
880
|
+
return breach?.data?.incidents[0]?.description || "";
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
expect(
|
|
884
|
+
descriptionOf("rum-session-replay-daily-budget-nearly-spent", "Shop"),
|
|
885
|
+
).toBe(
|
|
886
|
+
"This project has used 80% of today's session replay upload limit, which all of its RUM applications share. At 100% every recorder in the project is told to stop until 00:00 UTC. To make the rest of the day last, open the Replay Policy page of the busiest applications and lower the Sample percentage, upload only On error or frustration, or narrow the Allowed origins so staging traffic stops spending it. Self-hosted: the limit is SESSION_REPLAY_MAX_BYTES_PER_PROJECT_PER_DAY.",
|
|
887
|
+
);
|
|
888
|
+
expect(descriptionOf("rum-session-replay-daily-budget-spent", "Shop")).toBe(
|
|
889
|
+
"This project has spent today's session replay upload limit, which all of its RUM applications share: every recorder in the project has been told to stop, and nothing more is recorded until 00:00 UTC. This resolves on its own at about 00:10-00:15 UTC, once the last reading over the limit has left the monitor's 15-minute window. To make tomorrow's limit last, lower the Sample percentage, upload only On error or frustration, or narrow the Allowed origins on the busiest applications' Replay Policy page. Self-hosted: the limit is SESSION_REPLAY_MAX_BYTES_PER_PROJECT_PER_DAY.",
|
|
890
|
+
);
|
|
891
|
+
expect(
|
|
892
|
+
descriptionOf("rum-session-replay-monthly-budget-nearly-spent", "Shop"),
|
|
893
|
+
).toBe(
|
|
894
|
+
"Shop has used 80% of its monthly session replay budget. At 100% its recorders are told to stop until the 1st of next month (UTC). Raise the Monthly budget on its Replay Policy page, lower the Sample percentage, or upload only On error or frustration.",
|
|
895
|
+
);
|
|
896
|
+
expect(
|
|
897
|
+
descriptionOf("rum-session-replay-monthly-budget-spent", "Shop"),
|
|
898
|
+
).toBe(
|
|
899
|
+
"Shop has spent its monthly session replay budget: its recorders have been told to stop, and nothing more is recorded until the 1st of next month (UTC) or until the budget is raised on its Replay Policy page. This resolves on its own.",
|
|
900
|
+
);
|
|
901
|
+
|
|
902
|
+
// The daily text is about the project, so no application is named in it.
|
|
903
|
+
for (const id of DAILY_TEMPLATE_IDS) {
|
|
904
|
+
expect(descriptionOf(id, "Checkout Web")).not.toContain("Checkout Web");
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
for (const id of MONTHLY_TEMPLATE_IDS) {
|
|
908
|
+
expect(descriptionOf(id, "Checkout Web")).toMatch(/^Checkout Web has /);
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
test("every title carries the application it was created on", () => {
|
|
913
|
+
for (const id of BUDGET_TEMPLATE_IDS) {
|
|
914
|
+
const [breach]: Array<MonitorCriteriaInstance> = getCriteria(
|
|
915
|
+
getTemplate(id).getMonitorStep({
|
|
916
|
+
...buildArgs(),
|
|
917
|
+
monitorName: "Checkout Web",
|
|
918
|
+
}),
|
|
919
|
+
);
|
|
920
|
+
|
|
921
|
+
expect(breach?.data?.incidents[0]?.title).toMatch(
|
|
922
|
+
/^\[RUM\] .+ - Checkout Web$/,
|
|
923
|
+
);
|
|
924
|
+
expect(breach?.data?.alerts[0]?.title).toBe(
|
|
925
|
+
breach?.data?.incidents[0]?.title,
|
|
926
|
+
);
|
|
927
|
+
}
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
/*
|
|
931
|
+
* The Replay Health page's "Set up alerts" link opens the Recommendations
|
|
932
|
+
* tab searching for "budget", and that search matches a card's name,
|
|
933
|
+
* description, category and severity (RecommendationFilterUtil). So every
|
|
934
|
+
* budget template has to carry the word, and no other RUM template may, or
|
|
935
|
+
* the link lands on the wrong cards.
|
|
936
|
+
*/
|
|
937
|
+
test("the word the Health page searches for finds exactly the budget templates", () => {
|
|
938
|
+
const matching: Array<string> = getAllRumAlertTemplates()
|
|
939
|
+
.filter((template: RumAlertTemplate) => {
|
|
940
|
+
return [
|
|
941
|
+
template.name,
|
|
942
|
+
template.description,
|
|
943
|
+
template.category,
|
|
944
|
+
template.severity,
|
|
945
|
+
].some((field: string) => {
|
|
946
|
+
return field.toLowerCase().includes("budget");
|
|
947
|
+
});
|
|
948
|
+
})
|
|
949
|
+
.map((template: RumAlertTemplate) => {
|
|
950
|
+
return template.id;
|
|
951
|
+
});
|
|
952
|
+
|
|
953
|
+
expect(matching).toEqual(BUDGET_TEMPLATE_IDS);
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
/*
|
|
957
|
+
* A requirement is what keeps a template off applications its series is
|
|
958
|
+
* never posted for. The budget templates must all carry one, and nothing
|
|
959
|
+
* else may: a web vital gated by accident would vanish from every page.
|
|
960
|
+
*/
|
|
961
|
+
test("only the session replay templates carry a requirement, and all of them do", () => {
|
|
962
|
+
for (const template of getAllRumAlertTemplates()) {
|
|
963
|
+
expect(`${template.id}: ${Boolean(template.requirement)}`).toBe(
|
|
964
|
+
`${template.id}: ${template.category === "Session Replay"}`,
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
test.each(BUDGET_CASES)(
|
|
970
|
+
"$id survives the JSON round trip a saved monitor takes, scope and alias included",
|
|
971
|
+
(item: BudgetCase) => {
|
|
972
|
+
const original: MonitorStep = getTemplate(item.id).getMonitorStep(
|
|
973
|
+
buildArgs(),
|
|
974
|
+
);
|
|
975
|
+
const restored: MonitorStep = MonitorStep.fromJSON(
|
|
976
|
+
JSON.parse(JSON.stringify(original.toJSON())) as JSONObject,
|
|
977
|
+
);
|
|
978
|
+
const metricMonitor: MonitorStepMetricMonitor | undefined =
|
|
979
|
+
restored.data?.metricMonitor;
|
|
980
|
+
|
|
981
|
+
expect(
|
|
982
|
+
metricMonitor?.telemetryServiceIds?.map((id: ObjectID) => {
|
|
983
|
+
return id.toString();
|
|
984
|
+
}),
|
|
985
|
+
).toEqual([RUM_APPLICATION_ID.toString()]);
|
|
986
|
+
expect(metricMonitor?.rollingTime).toBe(RollingTime.Past15Minutes);
|
|
987
|
+
expect(
|
|
988
|
+
metricMonitor?.metricViewConfig.queryConfigs[0]?.metricAliasData
|
|
989
|
+
?.metricVariable,
|
|
990
|
+
).toBe(item.metricAlias);
|
|
991
|
+
expect(
|
|
992
|
+
metricMonitor?.metricViewConfig.queryConfigs[0]?.metricQueryData
|
|
993
|
+
.filterData.metricName,
|
|
994
|
+
).toBe(item.metricName);
|
|
995
|
+
|
|
996
|
+
const { breach, recovery }: BudgetFilters = getFilters(restored);
|
|
997
|
+
|
|
998
|
+
for (const filter of [breach, recovery]) {
|
|
999
|
+
expect(filter?.metricMonitorOptions?.metricAlias).toBe(
|
|
1000
|
+
item.metricAlias,
|
|
1001
|
+
);
|
|
1002
|
+
expect(filter?.metricMonitorOptions?.metricAggregationType).toBe(
|
|
1003
|
+
EvaluateOverTimeType.MaximumValue,
|
|
1004
|
+
);
|
|
1005
|
+
expect(filter?.metricMonitorOptions?.thresholdUnit).toBe("%");
|
|
1006
|
+
}
|
|
1007
|
+
},
|
|
1008
|
+
);
|
|
1009
|
+
});
|
|
1010
|
+
|
|
1011
|
+
/*
|
|
1012
|
+
* The gate. The sweep only posts the daily series for an application that has
|
|
1013
|
+
* session replay on and has recorded a replay, and the monthly series only
|
|
1014
|
+
* while it also has a monthly budget; a monitor over a series nobody posts
|
|
1015
|
+
* never fires and never says why. So each pair is offered only once its
|
|
1016
|
+
* series can exist - and "not known" never counts as yes.
|
|
1017
|
+
*/
|
|
1018
|
+
describe("getRumAlertTemplates", () => {
|
|
1019
|
+
test("offers the original seven when nothing is known about the application", () => {
|
|
1020
|
+
expect(offeredIds()).toEqual(CORE_TEMPLATE_IDS);
|
|
1021
|
+
expect(offeredIds(undefined)).toEqual(CORE_TEMPLATE_IDS);
|
|
1022
|
+
expect(offeredIds({})).toEqual(CORE_TEMPLATE_IDS);
|
|
1023
|
+
expect(
|
|
1024
|
+
offeredIds({
|
|
1025
|
+
sessionReplayEnabled: null,
|
|
1026
|
+
sessionReplayHasRecorded: null,
|
|
1027
|
+
sessionReplayMonthlyBudgetInGB: null,
|
|
1028
|
+
}),
|
|
1029
|
+
).toEqual(CORE_TEMPLATE_IDS);
|
|
1030
|
+
expect(
|
|
1031
|
+
offeredIds({
|
|
1032
|
+
sessionReplayEnabled: undefined,
|
|
1033
|
+
sessionReplayHasRecorded: undefined,
|
|
1034
|
+
sessionReplayMonthlyBudgetInGB: undefined,
|
|
1035
|
+
}),
|
|
1036
|
+
).toEqual(CORE_TEMPLATE_IDS);
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
test("adds the daily pair once the application has replay on and has recorded", () => {
|
|
1040
|
+
expect(
|
|
1041
|
+
offeredIds({
|
|
1042
|
+
sessionReplayEnabled: true,
|
|
1043
|
+
sessionReplayHasRecorded: true,
|
|
1044
|
+
}),
|
|
1045
|
+
).toEqual([...CORE_TEMPLATE_IDS, ...DAILY_TEMPLATE_IDS]);
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
test("adds the monthly pair once it also has a monthly budget", () => {
|
|
1049
|
+
const offered: Array<string> = offeredIds(FULL_CONTEXT);
|
|
1050
|
+
|
|
1051
|
+
expect(offered).toHaveLength(11);
|
|
1052
|
+
expect(offered).toEqual([
|
|
1053
|
+
...CORE_TEMPLATE_IDS,
|
|
1054
|
+
...DAILY_TEMPLATE_IDS,
|
|
1055
|
+
...MONTHLY_TEMPLATE_IDS,
|
|
1056
|
+
]);
|
|
1057
|
+
expect(offered).toEqual(
|
|
1058
|
+
getAllRumAlertTemplates().map((template: RumAlertTemplate) => {
|
|
1059
|
+
return template.id;
|
|
1060
|
+
}),
|
|
1061
|
+
);
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
test("counts a fractional budget - 0.5 is half a GiB, not none", () => {
|
|
1065
|
+
expect(
|
|
1066
|
+
offeredIds({ ...FULL_CONTEXT, sessionReplayMonthlyBudgetInGB: 0.5 }),
|
|
1067
|
+
).toHaveLength(11);
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
test.each([0, null, undefined, NaN, -1, Infinity, -Infinity])(
|
|
1071
|
+
"withholds only the monthly pair for a budget of %p",
|
|
1072
|
+
(budget: number | null | undefined) => {
|
|
1073
|
+
expect(
|
|
1074
|
+
offeredIds({
|
|
1075
|
+
sessionReplayEnabled: true,
|
|
1076
|
+
sessionReplayHasRecorded: true,
|
|
1077
|
+
sessionReplayMonthlyBudgetInGB: budget,
|
|
1078
|
+
}),
|
|
1079
|
+
).toEqual([...CORE_TEMPLATE_IDS, ...DAILY_TEMPLATE_IDS]);
|
|
1080
|
+
},
|
|
1081
|
+
);
|
|
1082
|
+
|
|
1083
|
+
test.each([false, null, undefined])(
|
|
1084
|
+
"withholds both pairs while session replay is %p for the application",
|
|
1085
|
+
(enabled: boolean | null | undefined) => {
|
|
1086
|
+
expect(
|
|
1087
|
+
offeredIds({ ...FULL_CONTEXT, sessionReplayEnabled: enabled }),
|
|
1088
|
+
).toEqual(CORE_TEMPLATE_IDS);
|
|
1089
|
+
},
|
|
1090
|
+
);
|
|
1091
|
+
|
|
1092
|
+
test.each([false, null, undefined])(
|
|
1093
|
+
"withholds both pairs, budget or not, while has-recorded is %p",
|
|
1094
|
+
(hasRecorded: boolean | null | undefined) => {
|
|
1095
|
+
expect(
|
|
1096
|
+
offeredIds({ ...FULL_CONTEXT, sessionReplayHasRecorded: hasRecorded }),
|
|
1097
|
+
).toEqual(CORE_TEMPLATE_IDS);
|
|
1098
|
+
expect(
|
|
1099
|
+
offeredIds({
|
|
1100
|
+
sessionReplayEnabled: true,
|
|
1101
|
+
sessionReplayHasRecorded: hasRecorded,
|
|
1102
|
+
}),
|
|
1103
|
+
).toEqual(CORE_TEMPLATE_IDS);
|
|
1104
|
+
},
|
|
1105
|
+
);
|
|
1106
|
+
|
|
1107
|
+
test("a budget alone offers nothing: the application also has to be recording", () => {
|
|
1108
|
+
expect(offeredIds({ sessionReplayMonthlyBudgetInGB: 10 })).toEqual(
|
|
1109
|
+
CORE_TEMPLATE_IDS,
|
|
1110
|
+
);
|
|
1111
|
+
expect(
|
|
1112
|
+
offeredIds({
|
|
1113
|
+
sessionReplayEnabled: false,
|
|
1114
|
+
sessionReplayHasRecorded: true,
|
|
1115
|
+
sessionReplayMonthlyBudgetInGB: 10,
|
|
1116
|
+
}),
|
|
1117
|
+
).toEqual(CORE_TEMPLATE_IDS);
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
/*
|
|
1121
|
+
* Only an explicit `true` and a real number count. Parsing what the API
|
|
1122
|
+
* hands back (a date string for has-recorded, a numeric string for the
|
|
1123
|
+
* budget) is the Dashboard registry's job, before it ever gets here.
|
|
1124
|
+
*/
|
|
1125
|
+
test("reads only an explicit true and a real number, never something truthy", () => {
|
|
1126
|
+
expect(
|
|
1127
|
+
offeredIds({
|
|
1128
|
+
sessionReplayEnabled: 1 as unknown as boolean,
|
|
1129
|
+
sessionReplayHasRecorded: true,
|
|
1130
|
+
}),
|
|
1131
|
+
).toEqual(CORE_TEMPLATE_IDS);
|
|
1132
|
+
expect(
|
|
1133
|
+
offeredIds({
|
|
1134
|
+
sessionReplayEnabled: true,
|
|
1135
|
+
sessionReplayHasRecorded:
|
|
1136
|
+
"2026-09-01T00:00:00.000Z" as unknown as boolean,
|
|
1137
|
+
}),
|
|
1138
|
+
).toEqual(CORE_TEMPLATE_IDS);
|
|
1139
|
+
expect(
|
|
1140
|
+
offeredIds({
|
|
1141
|
+
...FULL_CONTEXT,
|
|
1142
|
+
sessionReplayMonthlyBudgetInGB: "10" as unknown as number,
|
|
1143
|
+
}),
|
|
1144
|
+
).toEqual([...CORE_TEMPLATE_IDS, ...DAILY_TEMPLATE_IDS]);
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
test("offers every template without a requirement, whatever the context says", () => {
|
|
1148
|
+
const contexts: Array<RumAlertTemplateContext | undefined> = [
|
|
1149
|
+
undefined,
|
|
1150
|
+
{},
|
|
1151
|
+
FULL_CONTEXT,
|
|
1152
|
+
{ sessionReplayEnabled: false, sessionReplayHasRecorded: false },
|
|
1153
|
+
];
|
|
1154
|
+
|
|
1155
|
+
for (const context of contexts) {
|
|
1156
|
+
const offered: Array<string> = offeredIds(context);
|
|
1157
|
+
|
|
1158
|
+
for (const id of CORE_TEMPLATE_IDS) {
|
|
1159
|
+
expect(offered).toContain(id);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
test("does not expose its internal template array", () => {
|
|
1165
|
+
const first: Array<RumAlertTemplate> = getRumAlertTemplates(FULL_CONTEXT);
|
|
1166
|
+
first.length = 0;
|
|
1167
|
+
|
|
1168
|
+
expect(getRumAlertTemplates(FULL_CONTEXT)).toHaveLength(11);
|
|
1169
|
+
expect(getAllRumAlertTemplates()).toHaveLength(11);
|
|
1170
|
+
});
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
/*
|
|
1174
|
+
* A dismissal, and the created-monitor diff, resolve a template from its id
|
|
1175
|
+
* alone - with no idea what the application is offered today. The by-id
|
|
1176
|
+
* lookup therefore searches every template, gated or not.
|
|
1177
|
+
*/
|
|
1178
|
+
describe("getRumAlertTemplateById", () => {
|
|
1179
|
+
test.each(BUDGET_TEMPLATE_IDS)(
|
|
1180
|
+
"resolves %s even where it is not offered",
|
|
1181
|
+
(id: string) => {
|
|
1182
|
+
expect(offeredIds()).not.toContain(id);
|
|
1183
|
+
|
|
1184
|
+
const template: RumAlertTemplate | undefined =
|
|
1185
|
+
getRumAlertTemplateById(id);
|
|
1186
|
+
|
|
1187
|
+
expect(template).toBeDefined();
|
|
1188
|
+
expect(template?.id).toBe(id);
|
|
1189
|
+
expect(template?.category).toBe("Session Replay");
|
|
1190
|
+
},
|
|
1191
|
+
);
|
|
1192
|
+
});
|