@oneuptime/common 12.0.5 → 12.0.6
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/AIRun.ts +33 -0
- package/Models/DatabaseModels/DataSource.ts +744 -0
- package/Models/DatabaseModels/Index.ts +3 -0
- package/Models/DatabaseModels/ProjectCallSMSConfig.ts +10 -2
- package/Models/DatabaseModels/User.ts +2 -0
- package/Models/DatabaseModels/UserOnCallLog.ts +2 -0
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +2 -0
- package/Models/DatabaseModels/UserSession.ts +2 -0
- package/Models/DatabaseModels/UserTotpAuth.ts +6 -4
- package/Models/DatabaseModels/UserWebAuthn.ts +5 -3
- package/Server/API/AIInsightAPI.ts +47 -4
- package/Server/API/AIInvestigationAPI.ts +25 -0
- package/Server/API/DashboardAPI.ts +176 -492
- package/Server/API/DataSourceAPI.ts +268 -0
- package/Server/API/StatusPageAPI.ts +11 -1
- package/Server/API/UserAPI.ts +119 -0
- package/Server/Infrastructure/ClickhouseConfig.ts +59 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.ts +24 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.ts +76 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Infrastructure/Queue.ts +26 -0
- package/Server/Infrastructure/QueueWorker.ts +17 -0
- package/Server/Middleware/TelemetryIngest.ts +8 -3
- package/Server/Services/AIInsightService.ts +132 -12
- package/Server/Services/AIRunService.ts +34 -0
- package/Server/Services/AIService.ts +17 -2
- package/Server/Services/AlertService.ts +38 -32
- package/Server/Services/AnalyticsDatabaseService.ts +8 -4
- package/Server/Services/DataSourceService.ts +200 -0
- package/Server/Services/HostService.ts +92 -0
- package/Server/Services/IncidentService.ts +45 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MonitorService.ts +49 -0
- package/Server/Services/MonitorStatusService.ts +166 -0
- package/Server/Services/OpenTelemetryIngestService.ts +255 -184
- package/Server/Services/RumSessionPinService.ts +7 -21
- package/Server/Services/StatusPageSubscriberService.ts +13 -0
- package/Server/Services/UserService.ts +280 -9
- package/Server/Static/Vendor/README.md +62 -0
- package/Server/Static/Vendor/fonts/InterVariable.woff2 +0 -0
- package/Server/Static/Vendor/highlight/highlight.min.js +1244 -0
- package/Server/Static/Vendor/highlight/languages/apache.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/bash.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/c.min.js +41 -0
- package/Server/Static/Vendor/highlight/languages/cpp.min.js +47 -0
- package/Server/Static/Vendor/highlight/languages/csharp.min.js +49 -0
- package/Server/Static/Vendor/highlight/languages/css.min.js +31 -0
- package/Server/Static/Vendor/highlight/languages/diff.min.js +9 -0
- package/Server/Static/Vendor/highlight/languages/dns.min.js +11 -0
- package/Server/Static/Vendor/highlight/languages/dockerfile.min.js +8 -0
- package/Server/Static/Vendor/highlight/languages/go.min.js +20 -0
- package/Server/Static/Vendor/highlight/languages/graphql.min.js +12 -0
- package/Server/Static/Vendor/highlight/languages/http.min.js +14 -0
- package/Server/Static/Vendor/highlight/languages/ini.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/java.min.js +38 -0
- package/Server/Static/Vendor/highlight/languages/javascript.min.js +81 -0
- package/Server/Static/Vendor/highlight/languages/json.min.js +8 -0
- package/Server/Static/Vendor/highlight/languages/kotlin.min.js +46 -0
- package/Server/Static/Vendor/highlight/languages/lua.min.js +15 -0
- package/Server/Static/Vendor/highlight/languages/makefile.min.js +14 -0
- package/Server/Static/Vendor/highlight/languages/nginx.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/perl.min.js +41 -0
- package/Server/Static/Vendor/highlight/languages/php.min.js +59 -0
- package/Server/Static/Vendor/highlight/languages/powershell.min.js +39 -0
- package/Server/Static/Vendor/highlight/languages/python.min.js +42 -0
- package/Server/Static/Vendor/highlight/languages/r.min.js +26 -0
- package/Server/Static/Vendor/highlight/languages/ruby.min.js +54 -0
- package/Server/Static/Vendor/highlight/languages/rust.min.js +27 -0
- package/Server/Static/Vendor/highlight/languages/scala.min.js +28 -0
- package/Server/Static/Vendor/highlight/languages/sql.min.js +21 -0
- package/Server/Static/Vendor/highlight/languages/swift.min.js +68 -0
- package/Server/Static/Vendor/highlight/languages/typescript.min.js +99 -0
- package/Server/Static/Vendor/highlight/languages/xml.min.js +29 -0
- package/Server/Static/Vendor/highlight/languages/yaml.min.js +28 -0
- package/Server/Static/Vendor/highlight/styles/github-dark.min.css +10 -0
- package/Server/Static/Vendor/highlight/styles/vs2015.min.css +1 -0
- package/Server/Static/Vendor/tailwind/tailwind-3.4.5.js +21028 -0
- package/Server/Types/Database/Permissions/BasePermission.ts +7 -0
- package/Server/Types/Database/Permissions/DeletePermission.ts +2 -0
- package/Server/Types/Database/Permissions/ReadPermission.ts +3 -0
- package/Server/Types/Database/Permissions/TenantPermission.ts +101 -16
- package/Server/Utils/AI/CodeFix/FixRunBudget.ts +2 -2
- package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +90 -11
- package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +1 -0
- package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +1 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.ts +125 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +25 -15
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +256 -57
- package/Server/Utils/AI/SRE/Insights/InsightStore.ts +76 -18
- package/Server/Utils/AI/SRE/InvestigationTldr.ts +352 -0
- package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +7 -2
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +1793 -0
- package/Server/Utils/Dashboard/PublicDashboardViewConfig.ts +65 -0
- package/Server/Utils/DataSource/ConnectorRegistry.ts +53 -0
- package/Server/Utils/DataSource/Connectors/ClickHouseConnector.ts +338 -0
- package/Server/Utils/DataSource/Connectors/ElasticsearchConnector.ts +717 -0
- package/Server/Utils/DataSource/Connectors/LokiConnector.ts +606 -0
- package/Server/Utils/DataSource/Connectors/MySqlConnector.ts +307 -0
- package/Server/Utils/DataSource/Connectors/PostgresConnector.ts +260 -0
- package/Server/Utils/DataSource/Connectors/PrometheusConnector.ts +555 -0
- package/Server/Utils/DataSource/Connectors/RestApiConnector.ts +597 -0
- package/Server/Utils/DataSource/Connectors/SqlServerConnector.ts +318 -0
- package/Server/Utils/DataSource/EgressGuard.ts +446 -0
- package/Server/Utils/DataSource/HttpFetch.ts +221 -0
- package/Server/Utils/DataSource/SqlQueryGuard.ts +383 -0
- package/Server/Utils/DataSource/SqlResultShaper.ts +372 -0
- package/Server/Utils/DataSource/Types.ts +93 -0
- package/Server/Utils/Database/PostgresErrorTranslator.ts +172 -17
- package/Server/Utils/InProcessMemo.ts +141 -0
- package/Server/Utils/InstanceHealth/TelemetryIngestion.ts +628 -0
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +58 -0
- package/Server/Utils/Monitor/MonitorResource.ts +14 -0
- package/Server/Utils/Response.ts +12 -1
- package/Server/Utils/SSRFProtection.ts +237 -0
- package/Server/Utils/StartServer.ts +8 -0
- package/Server/Utils/StatusPageSubscriberWebhook.ts +30 -0
- package/Server/Utils/Telemetry/CaptureSpan.ts +30 -18
- package/Server/Utils/Telemetry/IngestionTimestamp.ts +75 -0
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +99 -7
- package/Server/Utils/Telemetry/Telemetry.ts +112 -1
- package/Server/Utils/Telemetry.ts +104 -3
- package/Server/Utils/VendorAssets.ts +165 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +28 -5
- package/Server/Utils/Workspace/Slack/Slack.ts +5 -0
- package/Server/Views/Partials/Head.ejs +21 -7
- package/Tests/App/AdminDashboard/AdminProjectsIdFilter.test.tsx +207 -0
- package/Tests/App/AdminDashboard/AdminUsersIdFilter.test.tsx +216 -0
- package/Tests/App/Dashboard/AIInsightViewActions.test.tsx +422 -0
- package/Tests/App/Dashboard/AddWidgetModal.test.tsx +10 -3
- package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +387 -0
- package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +199 -0
- package/Tests/App/Dashboard/DataSourceChartSyntheticConfig.test.tsx +736 -0
- package/Tests/App/Dashboard/DataSourceQueryEditor.test.tsx +868 -0
- package/Tests/App/Dashboard/DataSourceWidgetCatalog.test.ts +440 -0
- package/Tests/App/Dashboard/DataSourceWidgetFetching.test.tsx +2109 -0
- package/Tests/App/Dashboard/DataSourceWidgetViews.test.tsx +726 -0
- package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +447 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +514 -3
- package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +391 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +326 -0
- package/Tests/App/Dashboard/SideMenuHarness.tsx +187 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +6 -1
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +1858 -0
- package/Tests/Models/DatabaseModels/DataSourceModelSecrets.test.ts +70 -0
- package/Tests/Server/API/AIInvestigationAPI.test.ts +187 -0
- package/Tests/Server/API/DashboardPublicDataSourceStrip.test.ts +686 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +585 -823
- package/Tests/Server/API/DataSourceAPIRoutes.test.ts +486 -0
- package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +291 -0
- package/Tests/Server/API/UserAuthenticationAPI.test.ts +641 -0
- package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +441 -0
- package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +140 -0
- package/Tests/Server/Services/AIInsightService.test.ts +266 -11
- package/Tests/Server/Services/AIRunAnalysisTldrPersistence.test.ts +160 -0
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +4 -0
- package/Tests/Server/Services/AlertMetricResourceAttributes.test.ts +352 -0
- package/Tests/Server/Services/DataSourceServiceSettings.test.ts +244 -0
- package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +397 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +41 -2
- package/Tests/Server/Services/IncidentMetricResourceAttributes.test.ts +408 -0
- package/Tests/Server/Services/MonitorStatusServiceDeleteReferenceCleanup.test.ts +351 -0
- package/Tests/Server/Services/MonitorStatusServiceValidation.test.ts +171 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +398 -0
- package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +19 -0
- package/Tests/Server/Services/ProjectCallSMSConfigCredentialUniqueness.test.ts +305 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +36 -1
- package/Tests/Server/Services/RumSessionPinUniqueViolationRecovery.test.ts +163 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +973 -0
- package/Tests/Server/Types/Database/ObjectIdColumnQuery.test.ts +262 -0
- package/Tests/Server/Types/Database/Permissions/TenantPermission.test.ts +358 -0
- package/Tests/Server/Utils/AI/FixRunBudget.test.ts +2 -2
- package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +6 -1
- package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +121 -4
- package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +361 -10
- package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +292 -0
- package/Tests/Server/Utils/AI/InvestigationTldr.test.ts +623 -0
- package/Tests/Server/Utils/AI/InvestigationTldrWiring.test.ts +98 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +857 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardViewConfig.test.ts +480 -0
- package/Tests/Server/Utils/DataSource/ClickHouseConnector.test.ts +759 -0
- package/Tests/Server/Utils/DataSource/ConnectorRegistry.test.ts +37 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +645 -0
- package/Tests/Server/Utils/DataSource/ElasticsearchConnector.test.ts +1206 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +616 -0
- package/Tests/Server/Utils/DataSource/LokiConnector.test.ts +970 -0
- package/Tests/Server/Utils/DataSource/MySqlConnector.test.ts +935 -0
- package/Tests/Server/Utils/DataSource/PostgresConnector.test.ts +854 -0
- package/Tests/Server/Utils/DataSource/PrometheusConnector.test.ts +881 -0
- package/Tests/Server/Utils/DataSource/RestApiConnector.test.ts +1020 -0
- package/Tests/Server/Utils/DataSource/SqlQueryGuard.test.ts +425 -0
- package/Tests/Server/Utils/DataSource/SqlResultShaper.test.ts +555 -0
- package/Tests/Server/Utils/DataSource/SqlServerConnector.test.ts +934 -0
- package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +228 -7
- package/Tests/Server/Utils/InProcessMemo.test.ts +292 -0
- package/Tests/Server/Utils/InstanceHealth/TelemetryIngestion.test.ts +960 -0
- package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +103 -0
- package/Tests/Server/Utils/Monitor/MonitorMetricResourceAttributes.test.ts +336 -0
- package/Tests/Server/Utils/OfflineAssetHygiene.test.ts +521 -0
- package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +143 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +193 -0
- package/Tests/Server/Utils/StatusPageSubscriberWebhook.test.ts +101 -0
- package/Tests/Server/Utils/TailwindBuildCopy.test.ts +225 -0
- package/Tests/Server/Utils/Telemetry/ResourceHeartbeatL1Memo.test.ts +355 -0
- package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +128 -0
- package/Tests/Server/Utils/Telemetry/TelemetryUtilAttributeKeys.test.ts +381 -0
- package/Tests/Server/Utils/Telemetry.test.ts +87 -0
- package/Tests/Server/Utils/VendorAssetIntegrity.test.ts +343 -0
- package/Tests/Server/Utils/VendorAssets.test.ts +671 -0
- package/Tests/Server/Views/OfflineRender.test.ts +297 -0
- package/Tests/Types/Dashboard/DataSourceComponentTypes.test.ts +618 -0
- package/Tests/Types/DateClickhouseFormat.test.ts +192 -0
- package/Tests/Types/Password.test.ts +363 -0
- package/Tests/UI/Components/ConfirmModal.test.tsx +7 -0
- package/Tests/UI/Components/ErrorBoundary.test.tsx +53 -0
- package/Tests/UI/Components/Modal.test.tsx +281 -1
- package/Tests/UI/Components/ObjectIdFilterPipeline.test.tsx +396 -0
- package/Tests/UI/Components/StatusPage/ResourceGroupNavigator.test.tsx +1147 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +116 -1
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Tests/Utils/Analytics.test.ts +23 -0
- package/Tests/Utils/Dashboard/Components/DashboardDataSourceComponents.test.ts +640 -0
- package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +138 -0
- package/Tests/Utils/DataSource/DataSourceValueReducer.test.ts +526 -0
- package/Tests/Utils/Metrics/MetricResourceAttributeUtil.test.ts +691 -0
- package/Tests/Utils/StatusPage/GroupHierarchyView.test.ts +1452 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +931 -0
- package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +288 -0
- package/Tests/Utils/Telemetry/IngestionTimestamp.test.ts +170 -0
- package/Types/AI/AIInsightEvidence.ts +6 -0
- package/Types/Analytics/RevenueEvent.ts +31 -0
- package/Types/Dashboard/DashboardComponentType.ts +31 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.ts +27 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.ts +32 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.ts +30 -0
- package/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.ts +55 -0
- package/Types/DataSource/DataSourceLimits.ts +62 -0
- package/Types/DataSource/DataSourceQueryConfig.ts +41 -0
- package/Types/DataSource/DataSourceTableResult.ts +38 -0
- package/Types/DataSource/DataSourceType.ts +213 -0
- package/Types/Date.ts +43 -3
- package/Types/Password.ts +64 -0
- package/Types/Permission.ts +46 -0
- package/Types/UserAuthenticationStatus.ts +34 -0
- package/UI/Components/Button/Button.tsx +1 -1
- package/UI/Components/ErrorBoundary.tsx +459 -108
- package/UI/Components/Icon/Icon.tsx +10 -9
- package/UI/Components/Modal/ConfirmModal.tsx +6 -1
- package/UI/Components/Modal/Modal.tsx +267 -35
- package/UI/Components/Modal/ModalFooter.tsx +6 -1
- package/UI/Components/MoreMenu/MoreMenu.tsx +19 -4
- package/UI/Components/MoreMenu/MoreMenuItem.tsx +6 -1
- package/UI/Components/StatusPage/ResourceGrid.tsx +314 -0
- package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +808 -0
- package/UI/Components/StatusPage/ResourceList.tsx +570 -0
- package/UI/Styles/Theme.css +18 -0
- package/UI/Utils/API/RequestOptions.ts +7 -0
- package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +1 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +1 -0
- package/UI/Utils/TestDataSource.ts +61 -0
- package/UI/esbuild-config.js +45 -0
- package/Utils/Analytics.ts +15 -0
- package/Utils/Dashboard/Components/DashboardDataSourceChartComponent.ts +88 -0
- package/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.ts +123 -0
- package/Utils/Dashboard/Components/DashboardDataSourceShared.ts +16 -0
- package/Utils/Dashboard/Components/DashboardDataSourceTableComponent.ts +72 -0
- package/Utils/Dashboard/Components/DashboardDataSourceValueComponent.ts +126 -0
- package/Utils/Dashboard/Components/Index.ts +28 -0
- package/Utils/DataSource/DataSourceQueryText.ts +94 -0
- package/Utils/DataSource/DataSourceValueReducer.ts +156 -0
- package/Utils/Metrics/MetricResourceAttributeUtil.ts +380 -0
- package/Utils/NetworkDiscovery/ScanTargetUtil.ts +8 -6
- package/Utils/StatusPage/GroupHierarchyView.ts +931 -0
- package/Utils/StatusPage/ResourceExplorer.ts +853 -0
- package/build/dist/Models/DatabaseModels/AIRun.js +34 -0
- package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DataSource.js +774 -0
- package/build/dist/Models/DatabaseModels/DataSource.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +14 -4
- package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +2 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +2 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSession.js +2 -0
- package/build/dist/Models/DatabaseModels/UserSession.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserTotpAuth.js +6 -4
- package/build/dist/Models/DatabaseModels/UserTotpAuth.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js +5 -3
- package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
- package/build/dist/Server/API/AIInsightAPI.js +34 -4
- package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
- package/build/dist/Server/API/AIInvestigationAPI.js +23 -0
- package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +119 -433
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/DataSourceAPI.js +173 -0
- package/build/dist/Server/API/DataSourceAPI.js.map +1 -0
- package/build/dist/Server/API/StatusPageAPI.js +11 -1
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/UserAPI.js +94 -2
- package/build/dist/Server/API/UserAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js +49 -0
- package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js +19 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js +64 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Queue.js +27 -0
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Infrastructure/QueueWorker.js +13 -0
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +8 -3
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIInsightService.js +110 -10
- package/build/dist/Server/Services/AIInsightService.js.map +1 -1
- package/build/dist/Server/Services/AIRunService.js +34 -0
- package/build/dist/Server/Services/AIRunService.js.map +1 -1
- package/build/dist/Server/Services/AIService.js +16 -2
- package/build/dist/Server/Services/AIService.js.map +1 -1
- package/build/dist/Server/Services/AlertService.js +28 -35
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +8 -4
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DataSourceService.js +159 -0
- package/build/dist/Server/Services/DataSourceService.js.map +1 -0
- package/build/dist/Server/Services/HostService.js +74 -0
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +35 -24
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +45 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusService.js +129 -0
- package/build/dist/Server/Services/MonitorStatusService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +222 -159
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +7 -15
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +10 -0
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +241 -10
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js +6 -0
- package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/DeletePermission.js +1 -0
- package/build/dist/Server/Types/Database/Permissions/DeletePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +2 -0
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +68 -12
- package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +2 -2
- package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +68 -8
- package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +1 -0
- package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +1 -0
- package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js +97 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js.map +1 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +17 -15
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +178 -54
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +65 -16
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js +303 -0
- package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js.map +1 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +1261 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js +47 -0
- package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js +42 -0
- package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js +187 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js +493 -0
- package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js +399 -0
- package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js +195 -0
- package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js +149 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js +362 -0
- package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js +342 -0
- package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js +186 -0
- package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +305 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +134 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js +331 -0
- package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/SqlResultShaper.js +280 -0
- package/build/dist/Server/Utils/DataSource/SqlResultShaper.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/Types.js +2 -0
- package/build/dist/Server/Utils/DataSource/Types.js.map +1 -0
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +103 -9
- package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
- package/build/dist/Server/Utils/InProcessMemo.js +113 -0
- package/build/dist/Server/Utils/InProcessMemo.js.map +1 -0
- package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js +406 -0
- package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +34 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +14 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +9 -1
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +192 -0
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +7 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js +24 -0
- package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +25 -11
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js +32 -0
- package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +92 -5
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +92 -6
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js +93 -6
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/VendorAssets.js +121 -0
- package/build/dist/Server/Utils/VendorAssets.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +25 -4
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +5 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/Analytics/RevenueEvent.js +26 -0
- package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js +27 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js +16 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceLimits.js +47 -0
- package/build/dist/Types/DataSource/DataSourceLimits.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceQueryConfig.js +10 -0
- package/build/dist/Types/DataSource/DataSourceQueryConfig.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceTableResult.js +14 -0
- package/build/dist/Types/DataSource/DataSourceTableResult.js.map +1 -0
- package/build/dist/Types/DataSource/DataSourceType.js +183 -0
- package/build/dist/Types/DataSource/DataSourceType.js.map +1 -0
- package/build/dist/Types/Date.js +38 -3
- package/build/dist/Types/Date.js.map +1 -1
- package/build/dist/Types/Password.js +56 -0
- package/build/dist/Types/Password.js.map +1 -0
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/UserAuthenticationStatus.js +2 -0
- package/build/dist/Types/UserAuthenticationStatus.js.map +1 -0
- package/build/dist/UI/Components/ErrorBoundary.js +388 -72
- package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +10 -4
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +178 -19
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js +3 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +9 -6
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +7 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +119 -0
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +354 -0
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -0
- package/build/dist/UI/Components/StatusPage/ResourceList.js +203 -0
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -0
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +1 -6
- package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +3 -8
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/TestDataSource.js +39 -0
- package/build/dist/UI/Utils/TestDataSource.js.map +1 -0
- package/build/dist/Utils/Analytics.js +4 -0
- package/build/dist/Utils/Analytics.js.map +1 -1
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js +79 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js +111 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js +15 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js +62 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js +112 -0
- package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/DataSource/DataSourceQueryText.js +64 -0
- package/build/dist/Utils/DataSource/DataSourceQueryText.js.map +1 -0
- package/build/dist/Utils/DataSource/DataSourceValueReducer.js +124 -0
- package/build/dist/Utils/DataSource/DataSourceValueReducer.js.map +1 -0
- package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js +281 -0
- package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +8 -6
- package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
- package/build/dist/Utils/StatusPage/GroupHierarchyView.js +560 -0
- package/build/dist/Utils/StatusPage/GroupHierarchyView.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js +519 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -0
- package/jest.config.json +1 -0
- package/package.json +5 -1
- package/tsconfig.json +12 -10
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import DatabaseService from "./DatabaseService";
|
|
2
|
+
import Model from "../../Models/DatabaseModels/DataSource";
|
|
3
|
+
import CreateBy from "../Types/Database/CreateBy";
|
|
4
|
+
import UpdateBy from "../Types/Database/UpdateBy";
|
|
5
|
+
import { OnCreate, OnUpdate } from "../Types/Database/Hooks";
|
|
6
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
7
|
+
import ObjectID from "../../Types/ObjectID";
|
|
8
|
+
import DataSourceType, {
|
|
9
|
+
DataSourceTypeUtil,
|
|
10
|
+
} from "../../Types/DataSource/DataSourceType";
|
|
11
|
+
import { DataSourceConnectionSettings } from "../Utils/DataSource/Types";
|
|
12
|
+
import Dictionary from "../../Types/Dictionary";
|
|
13
|
+
import { JSONObject } from "../../Types/JSON";
|
|
14
|
+
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
15
|
+
|
|
16
|
+
export class Service extends DatabaseService<Model> {
|
|
17
|
+
public constructor() {
|
|
18
|
+
super(Model);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Per-type shape validation so a broken data source fails at save time
|
|
23
|
+
* with a clear message, not at first query with a connector error.
|
|
24
|
+
*/
|
|
25
|
+
private validateDataSourceShape(data: {
|
|
26
|
+
dataSourceType?: DataSourceType | undefined;
|
|
27
|
+
url?: string | undefined;
|
|
28
|
+
databaseHost?: string | undefined;
|
|
29
|
+
}): void {
|
|
30
|
+
const dataSourceType: DataSourceType | undefined = data.dataSourceType;
|
|
31
|
+
|
|
32
|
+
if (!dataSourceType) {
|
|
33
|
+
return; // updates that don't touch the type/host/url skip validation.
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!DataSourceTypeUtil.getAllDataSourceTypes().includes(dataSourceType)) {
|
|
37
|
+
throw new BadDataException(`Unknown data source type: ${dataSourceType}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (DataSourceTypeUtil.isHttpBasedType(dataSourceType) && !data.url) {
|
|
41
|
+
throw new BadDataException(
|
|
42
|
+
`${dataSourceType} data sources require a URL.`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
DataSourceTypeUtil.isDatabaseType(dataSourceType) &&
|
|
48
|
+
!data.databaseHost
|
|
49
|
+
) {
|
|
50
|
+
throw new BadDataException(
|
|
51
|
+
`${dataSourceType} data sources require a database host.`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected override async onBeforeCreate(
|
|
57
|
+
createBy: CreateBy<Model>,
|
|
58
|
+
): Promise<OnCreate<Model>> {
|
|
59
|
+
this.validateDataSourceShape({
|
|
60
|
+
dataSourceType: createBy.data.dataSourceType,
|
|
61
|
+
url: createBy.data.url,
|
|
62
|
+
databaseHost: createBy.data.databaseHost,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return { createBy, carryForward: null };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
protected override async onBeforeUpdate(
|
|
69
|
+
updateBy: UpdateBy<Model>,
|
|
70
|
+
): Promise<OnUpdate<Model>> {
|
|
71
|
+
/*
|
|
72
|
+
* Only validate when the update touches the fields that participate in
|
|
73
|
+
* shape validation. Changing the TYPE of an existing source without
|
|
74
|
+
* also sending url/host can produce a source that fails validation on
|
|
75
|
+
* its own merits — so when dataSourceType changes, re-validate against
|
|
76
|
+
* the stored row's values merged with the update.
|
|
77
|
+
*/
|
|
78
|
+
const data: {
|
|
79
|
+
dataSourceType?: DataSourceType | undefined;
|
|
80
|
+
url?: string | undefined;
|
|
81
|
+
databaseHost?: string | undefined;
|
|
82
|
+
} = updateBy.data as unknown as {
|
|
83
|
+
dataSourceType?: DataSourceType | undefined;
|
|
84
|
+
url?: string | undefined;
|
|
85
|
+
databaseHost?: string | undefined;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
* Presence check, not truthiness — an update that CLEARS url or
|
|
90
|
+
* databaseHost (null / empty string) must still be validated, or an
|
|
91
|
+
* HTTP source could be stripped of its URL and break at query time.
|
|
92
|
+
*/
|
|
93
|
+
const updateData: Record<string, unknown> = updateBy.data as Record<
|
|
94
|
+
string,
|
|
95
|
+
unknown
|
|
96
|
+
>;
|
|
97
|
+
const touchesShape: boolean =
|
|
98
|
+
"dataSourceType" in updateData ||
|
|
99
|
+
"url" in updateData ||
|
|
100
|
+
"databaseHost" in updateData;
|
|
101
|
+
|
|
102
|
+
if (touchesShape) {
|
|
103
|
+
const existing: Model | null = await this.findOneBy({
|
|
104
|
+
query: updateBy.query,
|
|
105
|
+
select: {
|
|
106
|
+
_id: true,
|
|
107
|
+
dataSourceType: true,
|
|
108
|
+
url: true,
|
|
109
|
+
databaseHost: true,
|
|
110
|
+
},
|
|
111
|
+
props: { isRoot: true },
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* A field present in the update wins even when cleared (null/"" →
|
|
116
|
+
* undefined, which validation treats as missing); an absent field
|
|
117
|
+
* falls back to the stored row.
|
|
118
|
+
*/
|
|
119
|
+
this.validateDataSourceShape({
|
|
120
|
+
dataSourceType: data.dataSourceType || existing?.dataSourceType,
|
|
121
|
+
url: "url" in updateData ? data.url || undefined : existing?.url,
|
|
122
|
+
databaseHost:
|
|
123
|
+
"databaseHost" in updateData
|
|
124
|
+
? data.databaseHost || undefined
|
|
125
|
+
: existing?.databaseHost,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return { updateBy, carryForward: null };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/*
|
|
133
|
+
* Decrypted connection settings for the server-side connector paths
|
|
134
|
+
* (/test and /query). ROOT read — the caller MUST have already performed
|
|
135
|
+
* a user-scoped access check on this id (the LlmProviderAPI two-phase
|
|
136
|
+
* pattern). The returned object holds plaintext secrets: never serialize
|
|
137
|
+
* it into a response or a log line.
|
|
138
|
+
*/
|
|
139
|
+
@CaptureSpan()
|
|
140
|
+
public async getConnectionSettingsById(
|
|
141
|
+
dataSourceId: ObjectID,
|
|
142
|
+
): Promise<DataSourceConnectionSettings | null> {
|
|
143
|
+
if (!ObjectID.isValidUUID(dataSourceId.toString())) {
|
|
144
|
+
/*
|
|
145
|
+
* A non-uuid string in a uuid column is a Postgres cast error, not
|
|
146
|
+
* an empty result — shape-check before querying.
|
|
147
|
+
*/
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const dataSource: Model | null = await this.findOneById({
|
|
152
|
+
id: dataSourceId,
|
|
153
|
+
select: {
|
|
154
|
+
_id: true,
|
|
155
|
+
projectId: true,
|
|
156
|
+
dataSourceType: true,
|
|
157
|
+
url: true,
|
|
158
|
+
databaseHost: true,
|
|
159
|
+
databasePort: true,
|
|
160
|
+
databaseName: true,
|
|
161
|
+
username: true,
|
|
162
|
+
password: true,
|
|
163
|
+
apiToken: true,
|
|
164
|
+
customHeaders: true,
|
|
165
|
+
additionalOptions: true,
|
|
166
|
+
},
|
|
167
|
+
props: { isRoot: true },
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
if (!dataSource || !dataSource.dataSourceType) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let customHeaders: Dictionary<string> | undefined = undefined;
|
|
175
|
+
if (dataSource.customHeaders) {
|
|
176
|
+
customHeaders = {};
|
|
177
|
+
const headers: JSONObject = dataSource.customHeaders;
|
|
178
|
+
for (const key of Object.keys(headers)) {
|
|
179
|
+
if (headers[key] !== null && headers[key] !== undefined) {
|
|
180
|
+
customHeaders[key] = headers[key]!.toString();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
dataSourceType: dataSource.dataSourceType,
|
|
187
|
+
url: dataSource.url,
|
|
188
|
+
databaseHost: dataSource.databaseHost,
|
|
189
|
+
databasePort: dataSource.databasePort,
|
|
190
|
+
databaseName: dataSource.databaseName,
|
|
191
|
+
username: dataSource.username,
|
|
192
|
+
password: dataSource.password,
|
|
193
|
+
apiToken: dataSource.apiToken,
|
|
194
|
+
customHeaders: customHeaders,
|
|
195
|
+
additionalOptions: dataSource.additionalOptions,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export default new Service();
|
|
@@ -11,6 +11,7 @@ import QueryHelper from "../Types/Database/QueryHelper";
|
|
|
11
11
|
import OneUptimeDate from "../../Types/Date";
|
|
12
12
|
import LIMIT_MAX from "../../Types/Database/LimitMax";
|
|
13
13
|
import GlobalCache from "../Infrastructure/GlobalCache";
|
|
14
|
+
import InProcessMemo from "../Utils/InProcessMemo";
|
|
14
15
|
import logger, { LogAttributes } from "../Utils/Logger";
|
|
15
16
|
import { canonicalizeEntityValue } from "../../Utils/Telemetry/EntityKey";
|
|
16
17
|
import crypto from "crypto";
|
|
@@ -21,6 +22,46 @@ const LAST_SEEN_THROTTLE_SECONDS: number = 60;
|
|
|
21
22
|
const LABELS_APPLIED_CACHE_NAMESPACE: string = "host-labels-applied";
|
|
22
23
|
const LABELS_APPLIED_CACHE_TTL_SECONDS: number = 60;
|
|
23
24
|
|
|
25
|
+
/*
|
|
26
|
+
* What `findOrCreateByHostIdentifier` memoizes: the resolved row's id plus
|
|
27
|
+
* the identifier it converged to. A flat shape rather than the Model itself
|
|
28
|
+
* so a memo hit hands every caller a FRESH Model instance — the resolving
|
|
29
|
+
* call and a memoed call must not share one mutable entity object.
|
|
30
|
+
*/
|
|
31
|
+
interface HostResolution {
|
|
32
|
+
hostIdStr: string;
|
|
33
|
+
hostIdentifier: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/*
|
|
37
|
+
* Per-process memo for `(projectId, canonical hostIdentifier) -> Host`.
|
|
38
|
+
*
|
|
39
|
+
* `findOrCreateByHostIdentifier` ran an unconditional Postgres SELECT per
|
|
40
|
+
* call, and the metrics ingest path calls it once per unique host per job
|
|
41
|
+
* (the host-enrichment aggregation loop) on top of `autoDiscoverHost`'s
|
|
42
|
+
* Redis-cache misses — for a fleet of workers chewing hostmetrics batches
|
|
43
|
+
* that is a steady stream of identical case-insensitive lookups for rows
|
|
44
|
+
* that change never. Same L1 shape as the service-resolution memo in
|
|
45
|
+
* OpenTelemetryIngestService: 60-second TTL, bounded because host
|
|
46
|
+
* identifiers arrive from collector-controlled resource attributes.
|
|
47
|
+
*
|
|
48
|
+
* ONLY positive resolutions (the host exists / was just created) are
|
|
49
|
+
* memoized, and only on success. There is deliberately no negative
|
|
50
|
+
* caching: the miss path must keep falling through to the create, so a
|
|
51
|
+
* create that loses a concurrent race still throws its unique-violation
|
|
52
|
+
* into the existing catch-and-refetch handling unchanged. Staleness is a
|
|
53
|
+
* non-issue for the id itself (ids are immutable); a deleted host keeps
|
|
54
|
+
* resolving for up to the TTL, which the 24-hour host-id Redis cache in
|
|
55
|
+
* OtelIngestBaseService already dwarfs.
|
|
56
|
+
*/
|
|
57
|
+
const HOST_RESOLUTION_MEMO_TTL_IN_MS: number = 60 * 1000;
|
|
58
|
+
const HOST_RESOLUTION_MEMO_MAX_ENTRIES: number = 10_000;
|
|
59
|
+
const hostResolutionInProcessMemo: InProcessMemo<HostResolution> =
|
|
60
|
+
new InProcessMemo<HostResolution>({
|
|
61
|
+
ttlInMs: HOST_RESOLUTION_MEMO_TTL_IN_MS,
|
|
62
|
+
maxEntries: HOST_RESOLUTION_MEMO_MAX_ENTRIES,
|
|
63
|
+
});
|
|
64
|
+
|
|
24
65
|
export class Service extends DatabaseService<Model> {
|
|
25
66
|
public constructor() {
|
|
26
67
|
super(Model);
|
|
@@ -75,6 +116,24 @@ export class Service extends DatabaseService<Model> {
|
|
|
75
116
|
*/
|
|
76
117
|
const hostIdentifier: string = canonicalizeEntityValue(data.hostIdentifier);
|
|
77
118
|
|
|
119
|
+
/*
|
|
120
|
+
* L1: in-process memo. The canonical identifier is the memo key, so
|
|
121
|
+
* every casing of one host collapses onto the entry the previous batch
|
|
122
|
+
* wrote — the same folding the SQL predicate below performs. A hit
|
|
123
|
+
* skips the SELECT (and the already-converged identifier write) that
|
|
124
|
+
* the resolving call performed within the last minute.
|
|
125
|
+
*/
|
|
126
|
+
const memoKey: string = `${data.projectId.toString()}:${hostIdentifier}`;
|
|
127
|
+
const memoedResolution: HostResolution | undefined =
|
|
128
|
+
hostResolutionInProcessMemo.get(memoKey);
|
|
129
|
+
if (memoedResolution) {
|
|
130
|
+
const memoedHost: Model = new Model();
|
|
131
|
+
memoedHost._id = memoedResolution.hostIdStr;
|
|
132
|
+
memoedHost.projectId = data.projectId;
|
|
133
|
+
memoedHost.hostIdentifier = memoedResolution.hostIdentifier;
|
|
134
|
+
return memoedHost;
|
|
135
|
+
}
|
|
136
|
+
|
|
78
137
|
/*
|
|
79
138
|
* Look up case-insensitively. The unique guard on name/hostIdentifier
|
|
80
139
|
* (DatabaseService.checkUniqueColumnBy -> QueryHelper.findWithSameText)
|
|
@@ -131,6 +190,18 @@ export class Service extends DatabaseService<Model> {
|
|
|
131
190
|
}
|
|
132
191
|
}
|
|
133
192
|
|
|
193
|
+
/*
|
|
194
|
+
* Memoize the identifier the row ACTUALLY holds (post-convergence,
|
|
195
|
+
* or the legacy casing when the best-effort update failed) so a memo
|
|
196
|
+
* hit returns exactly what a repeated lookup would have.
|
|
197
|
+
*/
|
|
198
|
+
if (existingHost._id) {
|
|
199
|
+
hostResolutionInProcessMemo.set(memoKey, {
|
|
200
|
+
hostIdStr: existingHost._id.toString(),
|
|
201
|
+
hostIdentifier: existingHost.hostIdentifier || hostIdentifier,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
134
205
|
return existingHost;
|
|
135
206
|
}
|
|
136
207
|
|
|
@@ -149,6 +220,13 @@ export class Service extends DatabaseService<Model> {
|
|
|
149
220
|
},
|
|
150
221
|
});
|
|
151
222
|
|
|
223
|
+
if (createdHost._id) {
|
|
224
|
+
hostResolutionInProcessMemo.set(memoKey, {
|
|
225
|
+
hostIdStr: createdHost._id.toString(),
|
|
226
|
+
hostIdentifier: hostIdentifier,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
152
230
|
return createdHost;
|
|
153
231
|
} catch {
|
|
154
232
|
/*
|
|
@@ -173,6 +251,20 @@ export class Service extends DatabaseService<Model> {
|
|
|
173
251
|
});
|
|
174
252
|
|
|
175
253
|
if (reFetchedHost) {
|
|
254
|
+
/*
|
|
255
|
+
* The refetch after a lost create race emits the same SELECT as
|
|
256
|
+
* the cold lookup, and a first-contact stampede on a brand-new
|
|
257
|
+
* host is exactly when this branch runs hot — memoize it like the
|
|
258
|
+
* other two resolution paths (mirrors the service-resolution
|
|
259
|
+
* cache's create-race handling).
|
|
260
|
+
*/
|
|
261
|
+
if (reFetchedHost._id) {
|
|
262
|
+
hostResolutionInProcessMemo.set(memoKey, {
|
|
263
|
+
hostIdStr: reFetchedHost._id.toString(),
|
|
264
|
+
hostIdentifier: reFetchedHost.hostIdentifier || hostIdentifier,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
176
268
|
return reFetchedHost;
|
|
177
269
|
}
|
|
178
270
|
|
|
@@ -56,6 +56,7 @@ import { MetricPointType } from "../../Models/AnalyticsModels/Metric";
|
|
|
56
56
|
import ServiceType from "../../Types/Telemetry/ServiceType";
|
|
57
57
|
import OneUptimeDate from "../../Types/Date";
|
|
58
58
|
import TelemetryUtil from "../Utils/Telemetry/Telemetry";
|
|
59
|
+
import MetricResourceAttributeUtil from "../../Utils/Metrics/MetricResourceAttributeUtil";
|
|
59
60
|
import logger, { LogAttributes } from "../Utils/Logger";
|
|
60
61
|
import ProductAnalytics from "../Utils/ProductAnalytics";
|
|
61
62
|
import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
|
|
@@ -2063,6 +2064,18 @@ ${incident.remediationNotes || "No remediation notes provided."}
|
|
|
2063
2064
|
|
|
2064
2065
|
// only emit if the incident has been resolved
|
|
2065
2066
|
if (resolvedTimeline && resolvedTimeline.startsAt) {
|
|
2067
|
+
/*
|
|
2068
|
+
* Same dimension set as every other incident metric — including
|
|
2069
|
+
* oneuptime.label.* / oneuptime.customField.* — so a dashboard
|
|
2070
|
+
* grouped by a label does not silently lose this series.
|
|
2071
|
+
*/
|
|
2072
|
+
const {
|
|
2073
|
+
baseMetricAttributes,
|
|
2074
|
+
}: { baseMetricAttributes: JSONObject } =
|
|
2075
|
+
await this.getIncidentMetricContext({
|
|
2076
|
+
incidentId: incidentId,
|
|
2077
|
+
});
|
|
2078
|
+
|
|
2066
2079
|
const postmortemMetric: MutableMetric = new MutableMetric();
|
|
2067
2080
|
postmortemMetric.projectId = projectId;
|
|
2068
2081
|
postmortemMetric.primaryEntityId = incidentId;
|
|
@@ -2076,6 +2089,7 @@ ${incident.remediationNotes || "No remediation notes provided."}
|
|
|
2076
2089
|
resolvedTimeline.startsAt,
|
|
2077
2090
|
);
|
|
2078
2091
|
postmortemMetric.attributes = {
|
|
2092
|
+
...baseMetricAttributes,
|
|
2079
2093
|
incidentId: incidentId.toString(),
|
|
2080
2094
|
projectId: projectId.toString(),
|
|
2081
2095
|
};
|
|
@@ -2356,6 +2370,18 @@ ${incidentSeverity.name}
|
|
|
2356
2370
|
|
|
2357
2371
|
// emit severity change metric
|
|
2358
2372
|
try {
|
|
2373
|
+
/*
|
|
2374
|
+
* Same dimension set as every other incident metric — including
|
|
2375
|
+
* oneuptime.label.* / oneuptime.customField.* — so "severity
|
|
2376
|
+
* churn by product" is answerable from the metric store.
|
|
2377
|
+
*/
|
|
2378
|
+
const {
|
|
2379
|
+
baseMetricAttributes,
|
|
2380
|
+
}: { baseMetricAttributes: JSONObject } =
|
|
2381
|
+
await this.getIncidentMetricContext({
|
|
2382
|
+
incidentId: incidentId,
|
|
2383
|
+
});
|
|
2384
|
+
|
|
2359
2385
|
const severityChangeMetric: MutableMetric = new MutableMetric();
|
|
2360
2386
|
severityChangeMetric.projectId = projectId;
|
|
2361
2387
|
severityChangeMetric.primaryEntityId = incidentId;
|
|
@@ -2364,6 +2390,7 @@ ${incidentSeverity.name}
|
|
|
2364
2390
|
severityChangeMetric.metricPointId = `severity-change:${ObjectID.generate().toString()}`;
|
|
2365
2391
|
severityChangeMetric.value = 1;
|
|
2366
2392
|
severityChangeMetric.attributes = {
|
|
2393
|
+
...baseMetricAttributes,
|
|
2367
2394
|
incidentId: incidentId.toString(),
|
|
2368
2395
|
projectId: projectId.toString(),
|
|
2369
2396
|
newIncidentSeverityId: incidentSeverity._id?.toString() || "",
|
|
@@ -3008,6 +3035,16 @@ ${incidentSeverity.name}
|
|
|
3008
3035
|
_id: true,
|
|
3009
3036
|
name: true,
|
|
3010
3037
|
},
|
|
3038
|
+
/*
|
|
3039
|
+
* A project's own taxonomy. Both become metric attributes below so
|
|
3040
|
+
* dashboards can group MTTA/MTTR by the dimensions the project
|
|
3041
|
+
* actually thinks in.
|
|
3042
|
+
*/
|
|
3043
|
+
labels: {
|
|
3044
|
+
_id: true,
|
|
3045
|
+
name: true,
|
|
3046
|
+
},
|
|
3047
|
+
customFields: true,
|
|
3011
3048
|
},
|
|
3012
3049
|
props: {
|
|
3013
3050
|
isRoot: true,
|
|
@@ -3121,6 +3158,14 @@ ${incidentSeverity.name}
|
|
|
3121
3158
|
ownerUserNames: ownerUserNames.join(", "),
|
|
3122
3159
|
ownerTeamIds: ownerTeamIds.join(", "),
|
|
3123
3160
|
ownerTeamNames: ownerTeamNames.join(", "),
|
|
3161
|
+
/*
|
|
3162
|
+
* oneuptime.label.* / oneuptime.customField.* — namespaced, so they can
|
|
3163
|
+
* never collide with the unprefixed dimensions above.
|
|
3164
|
+
*/
|
|
3165
|
+
...MetricResourceAttributeUtil.getResourceAttributes({
|
|
3166
|
+
labels: incident.labels,
|
|
3167
|
+
customFields: incident.customFields,
|
|
3168
|
+
}),
|
|
3124
3169
|
};
|
|
3125
3170
|
|
|
3126
3171
|
return { incident, baseMetricAttributes };
|
package/Server/Services/Index.ts
CHANGED
|
@@ -70,6 +70,7 @@ import CephClusterOwnerRuleService from "./CephClusterOwnerRuleService";
|
|
|
70
70
|
import CephClusterOwnerTeamService from "./CephClusterOwnerTeamService";
|
|
71
71
|
import CephClusterOwnerUserService from "./CephClusterOwnerUserService";
|
|
72
72
|
import LlmProviderService from "./LlmProviderService";
|
|
73
|
+
import DataSourceService from "./DataSourceService";
|
|
73
74
|
import AuditLogService from "./AuditLogService";
|
|
74
75
|
import LogService from "./LogService";
|
|
75
76
|
import MailService from "./MailService";
|
|
@@ -369,6 +370,7 @@ const services: Array<BaseService> = [
|
|
|
369
370
|
CephClusterOwnerTeamService,
|
|
370
371
|
CephClusterOwnerUserService,
|
|
371
372
|
LlmProviderService,
|
|
373
|
+
DataSourceService,
|
|
372
374
|
|
|
373
375
|
MailService,
|
|
374
376
|
MonitorCustomFieldService,
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
AllowedActiveMonitorCountInFreePlan,
|
|
4
4
|
IsBillingEnabled,
|
|
5
5
|
} from "../EnvironmentConfig";
|
|
6
|
+
import { UpdateResult } from "typeorm";
|
|
7
|
+
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
|
|
6
8
|
import { ActiveMonitoringMeteredPlan } from "../Types/Billing/MeteredPlan/AllMeteredPlans";
|
|
7
9
|
import CreateBy from "../Types/Database/CreateBy";
|
|
8
10
|
import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
|
|
@@ -2263,5 +2265,52 @@ ${createdItem.description?.trim() || "No description provided."}
|
|
|
2263
2265
|
|
|
2264
2266
|
return monitor.name || "";
|
|
2265
2267
|
}
|
|
2268
|
+
|
|
2269
|
+
/**
|
|
2270
|
+
* Repoints the currentMonitorStatusId of ALREADY SOFT-DELETED monitor rows
|
|
2271
|
+
* away from monitor statuses that are about to be hard-deleted.
|
|
2272
|
+
*
|
|
2273
|
+
* A soft-deleted monitor keeps its physical row - and therefore its
|
|
2274
|
+
* currentMonitorStatusId foreign key, which is ON DELETE NO ACTION - so a
|
|
2275
|
+
* status that a since-deleted monitor last pointed at cannot be removed
|
|
2276
|
+
* until that dangling reference is cleared. This surfaced as an intermittent
|
|
2277
|
+
* "Monitor records still reference it" failure when Terraform destroyed a
|
|
2278
|
+
* fixture that deleted its monitors and then the custom statuses those
|
|
2279
|
+
* monitors had adopted.
|
|
2280
|
+
*
|
|
2281
|
+
* Only soft-deleted rows are touched: deleting a status that a LIVE monitor
|
|
2282
|
+
* is currently in still surfaces the referential-integrity guard, so a user
|
|
2283
|
+
* is never silently robbed of a monitor's visible status. Returns the number
|
|
2284
|
+
* of dead rows repointed.
|
|
2285
|
+
*/
|
|
2286
|
+
@CaptureSpan()
|
|
2287
|
+
public async repointDeletedMonitorsAwayFromStatuses(data: {
|
|
2288
|
+
fromMonitorStatusIds: Array<ObjectID>;
|
|
2289
|
+
toMonitorStatusId: ObjectID;
|
|
2290
|
+
projectId: ObjectID;
|
|
2291
|
+
}): Promise<number> {
|
|
2292
|
+
if (data.fromMonitorStatusIds.length === 0) {
|
|
2293
|
+
return 0;
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
const result: UpdateResult = await this.getRepository()
|
|
2297
|
+
.createQueryBuilder()
|
|
2298
|
+
.update(Model)
|
|
2299
|
+
.set({
|
|
2300
|
+
currentMonitorStatusId: data.toMonitorStatusId.toString(),
|
|
2301
|
+
} as unknown as QueryDeepPartialEntity<Model>)
|
|
2302
|
+
.where('"projectId" = :projectId', {
|
|
2303
|
+
projectId: data.projectId.toString(),
|
|
2304
|
+
})
|
|
2305
|
+
.andWhere('"deletedAt" IS NOT NULL')
|
|
2306
|
+
.andWhere('"currentMonitorStatusId" IN (:...fromIds)', {
|
|
2307
|
+
fromIds: data.fromMonitorStatusIds.map((id: ObjectID) => {
|
|
2308
|
+
return id.toString();
|
|
2309
|
+
}),
|
|
2310
|
+
})
|
|
2311
|
+
.execute();
|
|
2312
|
+
|
|
2313
|
+
return result.affected || 0;
|
|
2314
|
+
}
|
|
2266
2315
|
}
|
|
2267
2316
|
export default new Service();
|
|
@@ -11,6 +11,14 @@ import BadDataException from "../../Types/Exception/BadDataException";
|
|
|
11
11
|
import ObjectID from "../../Types/ObjectID";
|
|
12
12
|
import Model from "../../Models/DatabaseModels/MonitorStatus";
|
|
13
13
|
import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
|
|
14
|
+
/*
|
|
15
|
+
* Statically imported despite the MonitorService <-> MonitorStatusService
|
|
16
|
+
* cycle: both modules reference each other only from method bodies (never at
|
|
17
|
+
* module-init time), so the default binding is always resolved by the time
|
|
18
|
+
* these methods run. A dynamic import() cannot be used here - the App build's
|
|
19
|
+
* TypeScript module target rejects it (TS1323).
|
|
20
|
+
*/
|
|
21
|
+
import MonitorService from "./MonitorService";
|
|
14
22
|
|
|
15
23
|
export class Service extends DatabaseService<Model> {
|
|
16
24
|
public constructor() {
|
|
@@ -51,6 +59,17 @@ export class Service extends DatabaseService<Model> {
|
|
|
51
59
|
);
|
|
52
60
|
}
|
|
53
61
|
|
|
62
|
+
/*
|
|
63
|
+
* Clear dangling currentMonitorStatusId references held by ALREADY
|
|
64
|
+
* soft-deleted monitors before the hard-delete runs. A soft-deleted
|
|
65
|
+
* monitor keeps its row and its currentMonitorStatusId foreign key
|
|
66
|
+
* (ON DELETE NO ACTION), so a status a since-deleted monitor last adopted
|
|
67
|
+
* cannot be removed while that reference lingers - the intermittent
|
|
68
|
+
* "Monitor records still reference it" failure. Live monitors are left
|
|
69
|
+
* untouched (see repointDeletedMonitorsAwayFromStatuses).
|
|
70
|
+
*/
|
|
71
|
+
await this.clearDeletedMonitorReferences(deleteBy.query);
|
|
72
|
+
|
|
54
73
|
let monitorStatus: Model | null = null;
|
|
55
74
|
|
|
56
75
|
if (!deleteBy.props.isRoot) {
|
|
@@ -72,6 +91,153 @@ export class Service extends DatabaseService<Model> {
|
|
|
72
91
|
};
|
|
73
92
|
}
|
|
74
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Repoints soft-deleted monitors that still reference the statuses matched
|
|
96
|
+
* by `query` to each project's default (lowest-priority) operational status,
|
|
97
|
+
* falling back to any other remaining status when no operational status
|
|
98
|
+
* survives. This keeps the Monitor.currentMonitorStatusId foreign key from
|
|
99
|
+
* blocking a monitor-status delete on dead rows.
|
|
100
|
+
*/
|
|
101
|
+
private async clearDeletedMonitorReferences(
|
|
102
|
+
query: DeleteBy<Model>["query"],
|
|
103
|
+
): Promise<void> {
|
|
104
|
+
const statusesBeingDeleted: Array<Model> = await this.findBy({
|
|
105
|
+
query: query,
|
|
106
|
+
select: {
|
|
107
|
+
_id: true,
|
|
108
|
+
projectId: true,
|
|
109
|
+
},
|
|
110
|
+
limit: LIMIT_MAX,
|
|
111
|
+
skip: 0,
|
|
112
|
+
props: {
|
|
113
|
+
isRoot: true,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Group the statuses being deleted by project.
|
|
118
|
+
const byProject: Map<
|
|
119
|
+
string,
|
|
120
|
+
{ projectId: ObjectID; statusIds: Array<ObjectID> }
|
|
121
|
+
> = new Map();
|
|
122
|
+
|
|
123
|
+
for (const status of statusesBeingDeleted) {
|
|
124
|
+
if (!status.id || !status.projectId) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const key: string = status.projectId.toString();
|
|
129
|
+
|
|
130
|
+
if (!byProject.has(key)) {
|
|
131
|
+
byProject.set(key, { projectId: status.projectId, statusIds: [] });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
byProject.get(key)!.statusIds.push(status.id);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (byProject.size === 0) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
for (const { projectId, statusIds } of byProject.values()) {
|
|
142
|
+
const deletedSet: Set<string> = new Set(
|
|
143
|
+
statusIds.map((id: ObjectID) => {
|
|
144
|
+
return id.toString();
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const fallbackStatusId: ObjectID | undefined =
|
|
149
|
+
await this.findFallbackStatusId(projectId, deletedSet);
|
|
150
|
+
|
|
151
|
+
if (!fallbackStatusId) {
|
|
152
|
+
// Nothing valid to repoint to - leave the referential guard in place.
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
await MonitorService.repointDeletedMonitorsAwayFromStatuses({
|
|
157
|
+
fromMonitorStatusIds: statusIds,
|
|
158
|
+
toMonitorStatusId: fallbackStatusId,
|
|
159
|
+
projectId: projectId,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Picks the status a repointed monitor should fall back to: the project's
|
|
166
|
+
* default (lowest-priority) operational status that is not itself being
|
|
167
|
+
* deleted, or - if none survives - any other remaining status.
|
|
168
|
+
*/
|
|
169
|
+
private async findFallbackStatusId(
|
|
170
|
+
projectId: ObjectID,
|
|
171
|
+
deletedStatusIds: Set<string>,
|
|
172
|
+
): Promise<ObjectID | undefined> {
|
|
173
|
+
const operationalStatuses: Array<Model> = await this.findBy({
|
|
174
|
+
query: {
|
|
175
|
+
projectId: projectId,
|
|
176
|
+
isOperationalState: true,
|
|
177
|
+
},
|
|
178
|
+
select: {
|
|
179
|
+
_id: true,
|
|
180
|
+
},
|
|
181
|
+
sort: {
|
|
182
|
+
priority: SortOrder.Ascending,
|
|
183
|
+
createdAt: SortOrder.Ascending,
|
|
184
|
+
},
|
|
185
|
+
limit: LIMIT_MAX,
|
|
186
|
+
skip: 0,
|
|
187
|
+
props: {
|
|
188
|
+
isRoot: true,
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const operationalFallback: ObjectID | undefined = this.firstSurvivingId(
|
|
193
|
+
operationalStatuses,
|
|
194
|
+
deletedStatusIds,
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
if (operationalFallback) {
|
|
198
|
+
return operationalFallback;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// No operational status survives - repoint to any other remaining status.
|
|
202
|
+
const anyStatuses: Array<Model> = await this.findBy({
|
|
203
|
+
query: {
|
|
204
|
+
projectId: projectId,
|
|
205
|
+
},
|
|
206
|
+
select: {
|
|
207
|
+
_id: true,
|
|
208
|
+
},
|
|
209
|
+
sort: {
|
|
210
|
+
priority: SortOrder.Ascending,
|
|
211
|
+
},
|
|
212
|
+
limit: LIMIT_MAX,
|
|
213
|
+
skip: 0,
|
|
214
|
+
props: {
|
|
215
|
+
isRoot: true,
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
return this.firstSurvivingId(anyStatuses, deletedStatusIds);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Returns the id of the first status in `statuses` (already priority-sorted)
|
|
224
|
+
* that is not in `deletedStatusIds`, or undefined when none survives.
|
|
225
|
+
*/
|
|
226
|
+
private firstSurvivingId(
|
|
227
|
+
statuses: Array<Model>,
|
|
228
|
+
deletedStatusIds: Set<string>,
|
|
229
|
+
): ObjectID | undefined {
|
|
230
|
+
for (const status of statuses) {
|
|
231
|
+
const id: ObjectID | null | undefined = status.id;
|
|
232
|
+
|
|
233
|
+
if (id && !deletedStatusIds.has(id.toString())) {
|
|
234
|
+
return id;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
|
|
75
241
|
@CaptureSpan()
|
|
76
242
|
protected override async onDeleteSuccess(
|
|
77
243
|
onDelete: OnDelete<Model>,
|