@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,305 @@
|
|
|
1
|
+
import ProjectCallSMSConfig from "../../../Models/DatabaseModels/ProjectCallSMSConfig";
|
|
2
|
+
import InitialMigration from "../../../Server/Infrastructure/Postgres/SchemaMigrations/1717605043663-InitialMigration";
|
|
3
|
+
import { DropProjectCallSMSConfigCredentialUniques1786700000000 } from "../../../Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques";
|
|
4
|
+
import SchemaMigrations from "../../../Server/Infrastructure/Postgres/SchemaMigrations/Index";
|
|
5
|
+
import { QueryRunner, getMetadataArgsStorage } from "typeorm";
|
|
6
|
+
import type { ColumnMetadataArgs } from "typeorm/metadata-args/ColumnMetadataArgs";
|
|
7
|
+
import { describe, expect, jest, test } from "@jest/globals";
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* Issue #3020: POST/PUT /api/call-sms-config answered 500 {"error":"Server
|
|
11
|
+
* Error"} the moment a second config was given Twilio credentials that another
|
|
12
|
+
* row already held.
|
|
13
|
+
*
|
|
14
|
+
* ProjectCallSMSConfig's columns were modelled on GlobalConfig, a SINGLETON
|
|
15
|
+
* table whose every column carries a pointless `unique: true`. Copied onto a
|
|
16
|
+
* tenant-scoped, inherently multi-row table, that became a global UNIQUE on
|
|
17
|
+
* twilioAccountSID and twilioAuthToken — no two rows anywhere in the instance
|
|
18
|
+
* could share a Twilio account. Two legitimate setups were then impossible:
|
|
19
|
+
*
|
|
20
|
+
* 1. One account, two numbers. Poland requires a Local number for Voice and
|
|
21
|
+
* a Mobile number for SMS, so one project needs two configs on one
|
|
22
|
+
* account. This is what the issue was filed against.
|
|
23
|
+
* 2. Two projects, one account — the first project to save an account SID
|
|
24
|
+
* locked every other tenant out of it, and neither could see why.
|
|
25
|
+
*
|
|
26
|
+
* Two things must hold for the fix, and a regression in either one puts the
|
|
27
|
+
* 500 straight back:
|
|
28
|
+
* 1. neither credential column declares `unique: true` (a `unique: true`
|
|
29
|
+
* here is what makes schema:generate re-ADD the constraint as "drift"),
|
|
30
|
+
* 2. the migration drops both constraints AND is registered in
|
|
31
|
+
* SchemaMigrations/Index.ts — an unregistered migration never runs, so
|
|
32
|
+
* every existing database keeps the constraint.
|
|
33
|
+
*
|
|
34
|
+
* Pure metadata/mocks — no Postgres connection anywhere.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const CREDENTIAL_COLUMNS: Array<string> = [
|
|
38
|
+
"twilioAccountSID",
|
|
39
|
+
"twilioAuthToken",
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const ACCOUNT_SID_CONSTRAINT: string = "UQ_0886139eac04ad49627e446d477";
|
|
43
|
+
const AUTH_TOKEN_CONSTRAINT: string = "UQ_2eb1a240d549a7701b6e82d2f94";
|
|
44
|
+
|
|
45
|
+
function columnArgs(propertyName: string): ColumnMetadataArgs {
|
|
46
|
+
const args: ColumnMetadataArgs | undefined = getMetadataArgsStorage()
|
|
47
|
+
.columns.filter((column: ColumnMetadataArgs) => {
|
|
48
|
+
return column.target === ProjectCallSMSConfig;
|
|
49
|
+
})
|
|
50
|
+
.find((column: ColumnMetadataArgs) => {
|
|
51
|
+
return column.propertyName === propertyName;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (!args) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`ProjectCallSMSConfig.${propertyName} has no TypeORM @Column metadata`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return args;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function makeQueryRunner(): {
|
|
64
|
+
runner: QueryRunner;
|
|
65
|
+
query: jest.Mock;
|
|
66
|
+
} {
|
|
67
|
+
const query: jest.Mock = jest.fn(() => {
|
|
68
|
+
return Promise.resolve(undefined);
|
|
69
|
+
}) as unknown as jest.Mock;
|
|
70
|
+
|
|
71
|
+
/*
|
|
72
|
+
* InitialMigration short-circuits when it finds a "File" table, so that its
|
|
73
|
+
* CREATE TABLEs are not replayed over an existing database. Undefined means
|
|
74
|
+
* "empty database", which is the path that actually emits the SQL.
|
|
75
|
+
*/
|
|
76
|
+
const getTable: jest.Mock = jest.fn(() => {
|
|
77
|
+
return Promise.resolve(undefined);
|
|
78
|
+
}) as unknown as jest.Mock;
|
|
79
|
+
|
|
80
|
+
return { runner: { query, getTable } as unknown as QueryRunner, query };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function executedSql(query: jest.Mock): Array<string> {
|
|
84
|
+
return query.mock.calls.map((call: Array<unknown>) => {
|
|
85
|
+
return String(call[0]);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
describe("ProjectCallSMSConfig credential columns", () => {
|
|
90
|
+
test.each(CREDENTIAL_COLUMNS)(
|
|
91
|
+
"%s is not declared unique — a Twilio account can back more than one config",
|
|
92
|
+
(propertyName: string) => {
|
|
93
|
+
expect(columnArgs(propertyName).options.unique).toBe(false);
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
test.each(CREDENTIAL_COLUMNS)(
|
|
98
|
+
"%s is still nullable, so a config may exist before credentials are entered",
|
|
99
|
+
(propertyName: string) => {
|
|
100
|
+
expect(columnArgs(propertyName).options.nullable).toBe(true);
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
test("twilioPrimaryPhoneNumber is not unique either — two projects can share a number", () => {
|
|
105
|
+
expect(columnArgs("twilioPrimaryPhoneNumber").options.unique).toBe(false);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("no column on this table declares unique: true at all", () => {
|
|
109
|
+
/*
|
|
110
|
+
* The whole class of bug, not just the two columns the issue happened to
|
|
111
|
+
* name. Config identity is `name`, which is unique PER PROJECT through
|
|
112
|
+
* @UniqueColumnBy("projectId") — an app-level check, not a DB constraint.
|
|
113
|
+
* Nothing on a tenant-scoped provider-credential table should ever be
|
|
114
|
+
* globally unique, so the correct count is zero.
|
|
115
|
+
*/
|
|
116
|
+
const uniqueColumns: Array<string> = getMetadataArgsStorage()
|
|
117
|
+
.columns.filter((column: ColumnMetadataArgs) => {
|
|
118
|
+
return (
|
|
119
|
+
column.target === ProjectCallSMSConfig &&
|
|
120
|
+
column.options.unique === true
|
|
121
|
+
);
|
|
122
|
+
})
|
|
123
|
+
.map((column: ColumnMetadataArgs) => {
|
|
124
|
+
return column.propertyName;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(uniqueColumns).toEqual([]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("the columns are wide enough for real Twilio credentials", () => {
|
|
131
|
+
/*
|
|
132
|
+
* Guards the alternative explanation for the reported 500. A live account
|
|
133
|
+
* SID is 34 characters and an auth token 32, so truncation was never the
|
|
134
|
+
* cause — but if these ever narrowed below that, the same endpoint would
|
|
135
|
+
* start answering 500 again for an entirely different reason.
|
|
136
|
+
*/
|
|
137
|
+
for (const propertyName of CREDENTIAL_COLUMNS) {
|
|
138
|
+
expect(Number(columnArgs(propertyName).options.length)).toBeGreaterThan(
|
|
139
|
+
34,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("DropProjectCallSMSConfigCredentialUniques migration", () => {
|
|
146
|
+
test("up() drops both credential constraints", async () => {
|
|
147
|
+
const { runner, query } = makeQueryRunner();
|
|
148
|
+
|
|
149
|
+
await new DropProjectCallSMSConfigCredentialUniques1786700000000().up(
|
|
150
|
+
runner,
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const sql: Array<string> = executedSql(query);
|
|
154
|
+
|
|
155
|
+
expect(sql).toHaveLength(2);
|
|
156
|
+
expect(sql[0]).toContain(ACCOUNT_SID_CONSTRAINT);
|
|
157
|
+
expect(sql[1]).toContain(AUTH_TOKEN_CONSTRAINT);
|
|
158
|
+
|
|
159
|
+
for (const statement of sql) {
|
|
160
|
+
expect(statement).toContain(`ALTER TABLE "ProjectCallSMSConfig"`);
|
|
161
|
+
expect(statement).toContain("DROP CONSTRAINT");
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("up() drops nothing else — no drift statements smuggled in", () => {
|
|
166
|
+
/*
|
|
167
|
+
* An autogenerated migration emits every difference it finds, so a
|
|
168
|
+
* regenerated file can quietly carry unrelated ALTERs. Both statements
|
|
169
|
+
* must be DROP CONSTRAINT against this one table.
|
|
170
|
+
*/
|
|
171
|
+
const { runner, query } = makeQueryRunner();
|
|
172
|
+
|
|
173
|
+
return new DropProjectCallSMSConfigCredentialUniques1786700000000()
|
|
174
|
+
.up(runner)
|
|
175
|
+
.then(() => {
|
|
176
|
+
for (const statement of executedSql(query)) {
|
|
177
|
+
expect(statement).not.toContain("ADD");
|
|
178
|
+
expect(statement).not.toContain("DROP COLUMN");
|
|
179
|
+
expect(statement).not.toMatch(
|
|
180
|
+
/ALTER TABLE "(?!ProjectCallSMSConfig)/,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("up() is idempotent — IF EXISTS, so a hand-dropped constraint does not fail the deploy", async () => {
|
|
187
|
+
/*
|
|
188
|
+
* Self-hosted operators hit by #3020 were told the workaround is to drop
|
|
189
|
+
* the constraint by hand. Without IF EXISTS this migration would abort on
|
|
190
|
+
* exactly the databases that most needed it.
|
|
191
|
+
*/
|
|
192
|
+
const { runner, query } = makeQueryRunner();
|
|
193
|
+
|
|
194
|
+
await new DropProjectCallSMSConfigCredentialUniques1786700000000().up(
|
|
195
|
+
runner,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
for (const statement of executedSql(query)) {
|
|
199
|
+
expect(statement).toContain("DROP CONSTRAINT IF EXISTS");
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("down() restores both constraints on the original columns", async () => {
|
|
204
|
+
const { runner, query } = makeQueryRunner();
|
|
205
|
+
|
|
206
|
+
await new DropProjectCallSMSConfigCredentialUniques1786700000000().down(
|
|
207
|
+
runner,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const sql: Array<string> = executedSql(query);
|
|
211
|
+
|
|
212
|
+
expect(sql).toHaveLength(2);
|
|
213
|
+
expect(sql.join("\n")).toContain(
|
|
214
|
+
`ADD CONSTRAINT "${AUTH_TOKEN_CONSTRAINT}" UNIQUE ("twilioAuthToken")`,
|
|
215
|
+
);
|
|
216
|
+
expect(sql.join("\n")).toContain(
|
|
217
|
+
`ADD CONSTRAINT "${ACCOUNT_SID_CONSTRAINT}" UNIQUE ("twilioAccountSID")`,
|
|
218
|
+
);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test("down() reuses the original constraint names, so up() can drop them again", async () => {
|
|
222
|
+
/*
|
|
223
|
+
* A rollback that invented new names would leave the next roll-forward
|
|
224
|
+
* dropping constraints that no longer exist and leaving the real ones in
|
|
225
|
+
* place — the bug would survive its own fix.
|
|
226
|
+
*/
|
|
227
|
+
const upRunner: {
|
|
228
|
+
runner: QueryRunner;
|
|
229
|
+
query: jest.Mock;
|
|
230
|
+
} = makeQueryRunner();
|
|
231
|
+
const downRunner: {
|
|
232
|
+
runner: QueryRunner;
|
|
233
|
+
query: jest.Mock;
|
|
234
|
+
} = makeQueryRunner();
|
|
235
|
+
const migration: DropProjectCallSMSConfigCredentialUniques1786700000000 =
|
|
236
|
+
new DropProjectCallSMSConfigCredentialUniques1786700000000();
|
|
237
|
+
|
|
238
|
+
await migration.up(upRunner.runner);
|
|
239
|
+
await migration.down(downRunner.runner);
|
|
240
|
+
|
|
241
|
+
for (const constraint of [ACCOUNT_SID_CONSTRAINT, AUTH_TOKEN_CONSTRAINT]) {
|
|
242
|
+
expect(executedSql(upRunner.query).join("\n")).toContain(constraint);
|
|
243
|
+
expect(executedSql(downRunner.query).join("\n")).toContain(constraint);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("targets the constraint names the InitialMigration actually created", () => {
|
|
248
|
+
/*
|
|
249
|
+
* The names are opaque TypeORM hashes. If they were mistyped, up() would
|
|
250
|
+
* silently drop nothing (IF EXISTS makes that a no-op rather than an
|
|
251
|
+
* error) and every database would keep the constraint. Pin them against
|
|
252
|
+
* the CREATE TABLE that introduced them.
|
|
253
|
+
*/
|
|
254
|
+
const { runner, query } = makeQueryRunner();
|
|
255
|
+
|
|
256
|
+
return new InitialMigration().up(runner).then(() => {
|
|
257
|
+
const createTable: string | undefined = executedSql(query).find(
|
|
258
|
+
(statement: string) => {
|
|
259
|
+
return statement.includes(`CREATE TABLE "ProjectCallSMSConfig"`);
|
|
260
|
+
},
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
expect(createTable).toBeDefined();
|
|
264
|
+
expect(createTable).toContain(
|
|
265
|
+
`CONSTRAINT "${ACCOUNT_SID_CONSTRAINT}" UNIQUE ("twilioAccountSID")`,
|
|
266
|
+
);
|
|
267
|
+
expect(createTable).toContain(
|
|
268
|
+
`CONSTRAINT "${AUTH_TOKEN_CONSTRAINT}" UNIQUE ("twilioAuthToken")`,
|
|
269
|
+
);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test("is registered in SchemaMigrations/Index.ts", () => {
|
|
274
|
+
expect(SchemaMigrations).toContain(
|
|
275
|
+
DropProjectCallSMSConfigCredentialUniques1786700000000,
|
|
276
|
+
);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test("is registered exactly once", () => {
|
|
280
|
+
const occurrences: number = SchemaMigrations.filter(
|
|
281
|
+
(migration: unknown) => {
|
|
282
|
+
return (
|
|
283
|
+
migration === DropProjectCallSMSConfigCredentialUniques1786700000000
|
|
284
|
+
);
|
|
285
|
+
},
|
|
286
|
+
).length;
|
|
287
|
+
|
|
288
|
+
expect(occurrences).toBe(1);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test("runs after the migration that created the constraints", () => {
|
|
292
|
+
/*
|
|
293
|
+
* TypeORM executes registered migrations in array order. Dropping a
|
|
294
|
+
* constraint before the CREATE TABLE that declares it is a no-op that
|
|
295
|
+
* leaves the constraint in place once the table finally arrives.
|
|
296
|
+
*/
|
|
297
|
+
const createIndex: number = SchemaMigrations.indexOf(InitialMigration);
|
|
298
|
+
const dropIndex: number = SchemaMigrations.indexOf(
|
|
299
|
+
DropProjectCallSMSConfigCredentialUniques1786700000000,
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
expect(createIndex).toBeGreaterThanOrEqual(0);
|
|
303
|
+
expect(dropIndex).toBeGreaterThan(createIndex);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* PasswordHash carries a pre-existing TS5.9 diagnostic that fails any suite
|
|
3
|
+
* whose runtime require graph reaches it (DatabaseService, the base class of
|
|
4
|
+
* every concrete service, imports it). Nothing password-related is under
|
|
5
|
+
* test here, so the module is replaced WITH A FACTORY — an automock would
|
|
6
|
+
* still require (and type-check) the real file.
|
|
7
|
+
*/
|
|
8
|
+
jest.mock("../../../Server/Utils/PasswordHash", () => {
|
|
9
|
+
return {
|
|
10
|
+
__esModule: true,
|
|
11
|
+
default: {
|
|
12
|
+
hash: jest.fn(),
|
|
13
|
+
verify: jest.fn(),
|
|
14
|
+
generateSalt: jest.fn(),
|
|
15
|
+
needsUpgrade: jest.fn(),
|
|
16
|
+
applyPepper: jest.fn(),
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
1
21
|
import CephClusterService from "../../../Server/Services/CephClusterService";
|
|
2
22
|
import CloudResourceService from "../../../Server/Services/CloudResourceService";
|
|
3
23
|
import DockerHostService from "../../../Server/Services/DockerHostService";
|
|
@@ -10,6 +30,7 @@ import PodmanHostService from "../../../Server/Services/PodmanHostService";
|
|
|
10
30
|
import ProxmoxClusterService from "../../../Server/Services/ProxmoxClusterService";
|
|
11
31
|
import RumApplicationService from "../../../Server/Services/RumApplicationService";
|
|
12
32
|
import ServerlessFunctionService from "../../../Server/Services/ServerlessFunctionService";
|
|
33
|
+
import ResourceHeartbeat from "../../../Server/Utils/Telemetry/ResourceHeartbeat";
|
|
13
34
|
import SingleFlight from "../../../Server/Utils/SingleFlight";
|
|
14
35
|
import ObjectID from "../../../Types/ObjectID";
|
|
15
36
|
import {
|
|
@@ -304,10 +325,15 @@ describe.each(SERVICE_CASES)(
|
|
|
304
325
|
return writes[writes.length - 1]!.data;
|
|
305
326
|
}
|
|
306
327
|
|
|
307
|
-
/**
|
|
328
|
+
/**
|
|
329
|
+
* Re-opens the liveness window without touching the enrichment gates.
|
|
330
|
+
* The in-process recent-heartbeat memo is capped at the liveness
|
|
331
|
+
* window, so its entries have expired by then too.
|
|
332
|
+
*/
|
|
308
333
|
function expireLivenessWindow(): void {
|
|
309
334
|
cache.delete(`${namespace}:${RESOURCE_ID.toString()}`);
|
|
310
335
|
SingleFlight.clear();
|
|
336
|
+
ResourceHeartbeat.clearRecentHeartbeatMemo();
|
|
311
337
|
}
|
|
312
338
|
|
|
313
339
|
beforeEach(() => {
|
|
@@ -316,12 +342,21 @@ describe.each(SERVICE_CASES)(
|
|
|
316
342
|
deletedCacheKeys = [];
|
|
317
343
|
writeLands = true;
|
|
318
344
|
SingleFlight.clear();
|
|
345
|
+
/*
|
|
346
|
+
* Each case reuses one RESOURCE_ID across tests, so the settled-
|
|
347
|
+
* heartbeat memo from a previous test must be treated as expired —
|
|
348
|
+
* exactly as the fresh `cache` map treats the Redis TTLs. The memo's
|
|
349
|
+
* own behaviour is pinned in
|
|
350
|
+
* Utils/Telemetry/ResourceHeartbeatL1Memo.test.ts.
|
|
351
|
+
*/
|
|
352
|
+
ResourceHeartbeat.clearRecentHeartbeatMemo();
|
|
319
353
|
mockCache();
|
|
320
354
|
});
|
|
321
355
|
|
|
322
356
|
afterEach(() => {
|
|
323
357
|
jest.restoreAllMocks();
|
|
324
358
|
SingleFlight.clear();
|
|
359
|
+
ResourceHeartbeat.clearRecentHeartbeatMemo();
|
|
325
360
|
});
|
|
326
361
|
|
|
327
362
|
describe("liveness columns", () => {
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import DatabaseService from "../../../Server/Services/DatabaseService";
|
|
2
|
+
import RumSessionPinService from "../../../Server/Services/RumSessionPinService";
|
|
3
|
+
import PostgresErrorTranslator from "../../../Server/Utils/Database/PostgresErrorTranslator";
|
|
4
|
+
import RumSessionPin from "../../../Models/DatabaseModels/RumSessionPin";
|
|
5
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
6
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
7
|
+
import CreateBy from "../../../Server/Types/Database/CreateBy";
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* Collateral guard for the issue #3020 fix.
|
|
12
|
+
*
|
|
13
|
+
* That fix taught PostgresErrorTranslator to turn a Postgres unique_violation
|
|
14
|
+
* (23505) into a BadDataException, so a duplicate reaches the client as a 400
|
|
15
|
+
* naming the field instead of a bare 500 "Server Error".
|
|
16
|
+
*
|
|
17
|
+
* RumSessionPinService is the one caller that RECOVERS from a unique violation
|
|
18
|
+
* rather than reporting it: pinning an already-pinned recording returns the
|
|
19
|
+
* existing pin instead of erroring, and the catch block closes the race between
|
|
20
|
+
* two concurrent pins. It used to detect the violation with a local
|
|
21
|
+
* `code === "23505"` check — which stopped matching the moment translation
|
|
22
|
+
* happened, because DatabaseService.create runs every failure through the
|
|
23
|
+
* translator BEFORE rethrowing. The error arriving in that catch is a
|
|
24
|
+
* BadDataException whose `code` is the numeric ExceptionCode, not a SQLSTATE.
|
|
25
|
+
*
|
|
26
|
+
* These tests pin the recovery to the translated shape, so translating more
|
|
27
|
+
* SQLSTATEs later cannot silently turn "already pinned" back into an error.
|
|
28
|
+
*
|
|
29
|
+
* DatabaseService.prototype.create is spied so super.create() is observable
|
|
30
|
+
* without a database.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
34
|
+
"00000000-0000-4000-8000-000000000001",
|
|
35
|
+
);
|
|
36
|
+
const RUM_APPLICATION_ID: ObjectID = new ObjectID(
|
|
37
|
+
"00000000-0000-4000-8000-000000000002",
|
|
38
|
+
);
|
|
39
|
+
const SESSION_ID: string = "session-abc";
|
|
40
|
+
|
|
41
|
+
/* The error DatabaseService.create actually throws after translation. */
|
|
42
|
+
function translatedUniqueViolation(): unknown {
|
|
43
|
+
return PostgresErrorTranslator.translate({
|
|
44
|
+
message:
|
|
45
|
+
'duplicate key value violates unique constraint "IDX_rum_session_pin_session"',
|
|
46
|
+
code: "23505",
|
|
47
|
+
table: "RumSessionPin",
|
|
48
|
+
detail:
|
|
49
|
+
'Key ("projectId", "rumApplicationId", "sessionId")=(00000000-0000-4000-8000-000000000001, 00000000-0000-4000-8000-000000000002, session-abc) already exists.',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function createBy(): CreateBy<RumSessionPin> {
|
|
54
|
+
const data: RumSessionPin = new RumSessionPin();
|
|
55
|
+
data.projectId = PROJECT_ID;
|
|
56
|
+
data.rumApplicationId = RUM_APPLICATION_ID;
|
|
57
|
+
data.sessionId = SESSION_ID;
|
|
58
|
+
|
|
59
|
+
return { data, props: { isRoot: true } } as CreateBy<RumSessionPin>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function existingPin(): RumSessionPin {
|
|
63
|
+
const pin: RumSessionPin = new RumSessionPin();
|
|
64
|
+
pin._id = "00000000-0000-4000-8000-000000000003";
|
|
65
|
+
pin.projectId = PROJECT_ID;
|
|
66
|
+
pin.rumApplicationId = RUM_APPLICATION_ID;
|
|
67
|
+
pin.sessionId = SESSION_ID;
|
|
68
|
+
|
|
69
|
+
return pin;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
describe("RumSessionPinService recovery from a translated unique violation", () => {
|
|
73
|
+
let createSpy: jest.SpyInstance;
|
|
74
|
+
let getPinSpy: jest.SpyInstance;
|
|
75
|
+
|
|
76
|
+
beforeEach(() => {
|
|
77
|
+
createSpy = jest.spyOn(DatabaseService.prototype, "create");
|
|
78
|
+
getPinSpy = jest.spyOn(RumSessionPinService, "getPinForSession");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
afterEach(() => {
|
|
82
|
+
jest.restoreAllMocks();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("the error thrown by create() really is translated, not raw", () => {
|
|
86
|
+
/*
|
|
87
|
+
* Guards the premise. If this stopped being a BadDataException the rest of
|
|
88
|
+
* these tests would be exercising a shape that no longer occurs.
|
|
89
|
+
*/
|
|
90
|
+
expect(translatedUniqueViolation()).toBeInstanceOf(BadDataException);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("a raced duplicate pin returns the existing pin instead of throwing", async () => {
|
|
94
|
+
const pin: RumSessionPin = existingPin();
|
|
95
|
+
|
|
96
|
+
/* Pre-check finds nothing; the racing request wins; the retry finds it. */
|
|
97
|
+
getPinSpy
|
|
98
|
+
.mockResolvedValueOnce(null as never)
|
|
99
|
+
.mockResolvedValueOnce(pin as never);
|
|
100
|
+
createSpy.mockRejectedValueOnce(translatedUniqueViolation() as never);
|
|
101
|
+
|
|
102
|
+
await expect(RumSessionPinService.create(createBy())).resolves.toBe(pin);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("the recovery is what returns it — create() was really attempted", async () => {
|
|
106
|
+
const pin: RumSessionPin = existingPin();
|
|
107
|
+
|
|
108
|
+
getPinSpy
|
|
109
|
+
.mockResolvedValueOnce(null as never)
|
|
110
|
+
.mockResolvedValueOnce(pin as never);
|
|
111
|
+
createSpy.mockRejectedValueOnce(translatedUniqueViolation() as never);
|
|
112
|
+
|
|
113
|
+
await RumSessionPinService.create(createBy());
|
|
114
|
+
|
|
115
|
+
expect(createSpy).toHaveBeenCalledTimes(1);
|
|
116
|
+
expect(getPinSpy).toHaveBeenCalledTimes(2);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("a unique violation with nothing to recover still surfaces", async () => {
|
|
120
|
+
/*
|
|
121
|
+
* If the row genuinely is not there, swallowing the error would report a
|
|
122
|
+
* pin that does not exist.
|
|
123
|
+
*/
|
|
124
|
+
const error: unknown = translatedUniqueViolation();
|
|
125
|
+
|
|
126
|
+
getPinSpy.mockResolvedValue(null as never);
|
|
127
|
+
createSpy.mockRejectedValueOnce(error as never);
|
|
128
|
+
|
|
129
|
+
await expect(RumSessionPinService.create(createBy())).rejects.toBe(error);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("an unrelated failure is rethrown untouched, not treated as a duplicate", async () => {
|
|
133
|
+
const error: BadDataException = new BadDataException("something else");
|
|
134
|
+
|
|
135
|
+
getPinSpy.mockResolvedValue(null as never);
|
|
136
|
+
createSpy.mockRejectedValueOnce(error as never);
|
|
137
|
+
|
|
138
|
+
await expect(RumSessionPinService.create(createBy())).rejects.toBe(error);
|
|
139
|
+
expect(getPinSpy).toHaveBeenCalledTimes(1);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("a translated FOREIGN KEY violation is not mistaken for a duplicate", async () => {
|
|
143
|
+
/*
|
|
144
|
+
* Both SQLSTATEs now translate to a BadDataException, so the recovery can
|
|
145
|
+
* no longer key off the exception type — only off the recorded SQLSTATE.
|
|
146
|
+
*/
|
|
147
|
+
const error: unknown = PostgresErrorTranslator.translate({
|
|
148
|
+
message: "insert violates foreign key constraint",
|
|
149
|
+
code: "23503",
|
|
150
|
+
table: "RumSessionPin",
|
|
151
|
+
detail:
|
|
152
|
+
'Key (rumApplicationId)=(00000000-0000-4000-8000-000000000002) is not present in table "RumApplication".',
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(error).toBeInstanceOf(BadDataException);
|
|
156
|
+
|
|
157
|
+
getPinSpy.mockResolvedValue(null as never);
|
|
158
|
+
createSpy.mockRejectedValueOnce(error as never);
|
|
159
|
+
|
|
160
|
+
await expect(RumSessionPinService.create(createBy())).rejects.toBe(error);
|
|
161
|
+
expect(getPinSpy).toHaveBeenCalledTimes(1);
|
|
162
|
+
});
|
|
163
|
+
});
|