@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.
Files changed (528) hide show
  1. package/Models/DatabaseModels/AIRun.ts +33 -0
  2. package/Models/DatabaseModels/DataSource.ts +744 -0
  3. package/Models/DatabaseModels/Index.ts +3 -0
  4. package/Models/DatabaseModels/ProjectCallSMSConfig.ts +10 -2
  5. package/Models/DatabaseModels/User.ts +2 -0
  6. package/Models/DatabaseModels/UserOnCallLog.ts +2 -0
  7. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +2 -0
  8. package/Models/DatabaseModels/UserSession.ts +2 -0
  9. package/Models/DatabaseModels/UserTotpAuth.ts +6 -4
  10. package/Models/DatabaseModels/UserWebAuthn.ts +5 -3
  11. package/Server/API/AIInsightAPI.ts +47 -4
  12. package/Server/API/AIInvestigationAPI.ts +25 -0
  13. package/Server/API/DashboardAPI.ts +176 -492
  14. package/Server/API/DataSourceAPI.ts +268 -0
  15. package/Server/API/StatusPageAPI.ts +11 -1
  16. package/Server/API/UserAPI.ts +119 -0
  17. package/Server/Infrastructure/ClickhouseConfig.ts +59 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.ts +39 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.ts +24 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.ts +76 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  22. package/Server/Infrastructure/Queue.ts +26 -0
  23. package/Server/Infrastructure/QueueWorker.ts +17 -0
  24. package/Server/Middleware/TelemetryIngest.ts +8 -3
  25. package/Server/Services/AIInsightService.ts +132 -12
  26. package/Server/Services/AIRunService.ts +34 -0
  27. package/Server/Services/AIService.ts +17 -2
  28. package/Server/Services/AlertService.ts +38 -32
  29. package/Server/Services/AnalyticsDatabaseService.ts +8 -4
  30. package/Server/Services/DataSourceService.ts +200 -0
  31. package/Server/Services/HostService.ts +92 -0
  32. package/Server/Services/IncidentService.ts +45 -0
  33. package/Server/Services/Index.ts +2 -0
  34. package/Server/Services/MonitorService.ts +49 -0
  35. package/Server/Services/MonitorStatusService.ts +166 -0
  36. package/Server/Services/OpenTelemetryIngestService.ts +255 -184
  37. package/Server/Services/RumSessionPinService.ts +7 -21
  38. package/Server/Services/StatusPageSubscriberService.ts +13 -0
  39. package/Server/Services/UserService.ts +280 -9
  40. package/Server/Static/Vendor/README.md +62 -0
  41. package/Server/Static/Vendor/fonts/InterVariable.woff2 +0 -0
  42. package/Server/Static/Vendor/highlight/highlight.min.js +1244 -0
  43. package/Server/Static/Vendor/highlight/languages/apache.min.js +15 -0
  44. package/Server/Static/Vendor/highlight/languages/bash.min.js +21 -0
  45. package/Server/Static/Vendor/highlight/languages/c.min.js +41 -0
  46. package/Server/Static/Vendor/highlight/languages/cpp.min.js +47 -0
  47. package/Server/Static/Vendor/highlight/languages/csharp.min.js +49 -0
  48. package/Server/Static/Vendor/highlight/languages/css.min.js +31 -0
  49. package/Server/Static/Vendor/highlight/languages/diff.min.js +9 -0
  50. package/Server/Static/Vendor/highlight/languages/dns.min.js +11 -0
  51. package/Server/Static/Vendor/highlight/languages/dockerfile.min.js +8 -0
  52. package/Server/Static/Vendor/highlight/languages/go.min.js +20 -0
  53. package/Server/Static/Vendor/highlight/languages/graphql.min.js +12 -0
  54. package/Server/Static/Vendor/highlight/languages/http.min.js +14 -0
  55. package/Server/Static/Vendor/highlight/languages/ini.min.js +15 -0
  56. package/Server/Static/Vendor/highlight/languages/java.min.js +38 -0
  57. package/Server/Static/Vendor/highlight/languages/javascript.min.js +81 -0
  58. package/Server/Static/Vendor/highlight/languages/json.min.js +8 -0
  59. package/Server/Static/Vendor/highlight/languages/kotlin.min.js +46 -0
  60. package/Server/Static/Vendor/highlight/languages/lua.min.js +15 -0
  61. package/Server/Static/Vendor/highlight/languages/makefile.min.js +14 -0
  62. package/Server/Static/Vendor/highlight/languages/nginx.min.js +21 -0
  63. package/Server/Static/Vendor/highlight/languages/perl.min.js +41 -0
  64. package/Server/Static/Vendor/highlight/languages/php.min.js +59 -0
  65. package/Server/Static/Vendor/highlight/languages/powershell.min.js +39 -0
  66. package/Server/Static/Vendor/highlight/languages/python.min.js +42 -0
  67. package/Server/Static/Vendor/highlight/languages/r.min.js +26 -0
  68. package/Server/Static/Vendor/highlight/languages/ruby.min.js +54 -0
  69. package/Server/Static/Vendor/highlight/languages/rust.min.js +27 -0
  70. package/Server/Static/Vendor/highlight/languages/scala.min.js +28 -0
  71. package/Server/Static/Vendor/highlight/languages/sql.min.js +21 -0
  72. package/Server/Static/Vendor/highlight/languages/swift.min.js +68 -0
  73. package/Server/Static/Vendor/highlight/languages/typescript.min.js +99 -0
  74. package/Server/Static/Vendor/highlight/languages/xml.min.js +29 -0
  75. package/Server/Static/Vendor/highlight/languages/yaml.min.js +28 -0
  76. package/Server/Static/Vendor/highlight/styles/github-dark.min.css +10 -0
  77. package/Server/Static/Vendor/highlight/styles/vs2015.min.css +1 -0
  78. package/Server/Static/Vendor/tailwind/tailwind-3.4.5.js +21028 -0
  79. package/Server/Types/Database/Permissions/BasePermission.ts +7 -0
  80. package/Server/Types/Database/Permissions/DeletePermission.ts +2 -0
  81. package/Server/Types/Database/Permissions/ReadPermission.ts +3 -0
  82. package/Server/Types/Database/Permissions/TenantPermission.ts +101 -16
  83. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +2 -2
  84. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +90 -11
  85. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +1 -0
  86. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +1 -0
  87. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.ts +125 -0
  88. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +25 -15
  89. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +256 -57
  90. package/Server/Utils/AI/SRE/Insights/InsightStore.ts +76 -18
  91. package/Server/Utils/AI/SRE/InvestigationTldr.ts +352 -0
  92. package/Server/Utils/AnalyticsDatabase/InsertDedupContext.ts +7 -2
  93. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +1793 -0
  94. package/Server/Utils/Dashboard/PublicDashboardViewConfig.ts +65 -0
  95. package/Server/Utils/DataSource/ConnectorRegistry.ts +53 -0
  96. package/Server/Utils/DataSource/Connectors/ClickHouseConnector.ts +338 -0
  97. package/Server/Utils/DataSource/Connectors/ElasticsearchConnector.ts +717 -0
  98. package/Server/Utils/DataSource/Connectors/LokiConnector.ts +606 -0
  99. package/Server/Utils/DataSource/Connectors/MySqlConnector.ts +307 -0
  100. package/Server/Utils/DataSource/Connectors/PostgresConnector.ts +260 -0
  101. package/Server/Utils/DataSource/Connectors/PrometheusConnector.ts +555 -0
  102. package/Server/Utils/DataSource/Connectors/RestApiConnector.ts +597 -0
  103. package/Server/Utils/DataSource/Connectors/SqlServerConnector.ts +318 -0
  104. package/Server/Utils/DataSource/EgressGuard.ts +446 -0
  105. package/Server/Utils/DataSource/HttpFetch.ts +221 -0
  106. package/Server/Utils/DataSource/SqlQueryGuard.ts +383 -0
  107. package/Server/Utils/DataSource/SqlResultShaper.ts +372 -0
  108. package/Server/Utils/DataSource/Types.ts +93 -0
  109. package/Server/Utils/Database/PostgresErrorTranslator.ts +172 -17
  110. package/Server/Utils/InProcessMemo.ts +141 -0
  111. package/Server/Utils/InstanceHealth/TelemetryIngestion.ts +628 -0
  112. package/Server/Utils/Monitor/MonitorMetricUtil.ts +58 -0
  113. package/Server/Utils/Monitor/MonitorResource.ts +14 -0
  114. package/Server/Utils/Response.ts +12 -1
  115. package/Server/Utils/SSRFProtection.ts +237 -0
  116. package/Server/Utils/StartServer.ts +8 -0
  117. package/Server/Utils/StatusPageSubscriberWebhook.ts +30 -0
  118. package/Server/Utils/Telemetry/CaptureSpan.ts +30 -18
  119. package/Server/Utils/Telemetry/IngestionTimestamp.ts +75 -0
  120. package/Server/Utils/Telemetry/ResourceHeartbeat.ts +99 -7
  121. package/Server/Utils/Telemetry/Telemetry.ts +112 -1
  122. package/Server/Utils/Telemetry.ts +104 -3
  123. package/Server/Utils/VendorAssets.ts +165 -0
  124. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +28 -5
  125. package/Server/Utils/Workspace/Slack/Slack.ts +5 -0
  126. package/Server/Views/Partials/Head.ejs +21 -7
  127. package/Tests/App/AdminDashboard/AdminProjectsIdFilter.test.tsx +207 -0
  128. package/Tests/App/AdminDashboard/AdminUsersIdFilter.test.tsx +216 -0
  129. package/Tests/App/Dashboard/AIInsightViewActions.test.tsx +422 -0
  130. package/Tests/App/Dashboard/AddWidgetModal.test.tsx +10 -3
  131. package/Tests/App/Dashboard/AlertsSideMenu.test.tsx +387 -0
  132. package/Tests/App/Dashboard/ChatActivityFeed.test.tsx +199 -0
  133. package/Tests/App/Dashboard/DataSourceChartSyntheticConfig.test.tsx +736 -0
  134. package/Tests/App/Dashboard/DataSourceQueryEditor.test.tsx +868 -0
  135. package/Tests/App/Dashboard/DataSourceWidgetCatalog.test.ts +440 -0
  136. package/Tests/App/Dashboard/DataSourceWidgetFetching.test.tsx +2109 -0
  137. package/Tests/App/Dashboard/DataSourceWidgetViews.test.tsx +726 -0
  138. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +447 -0
  139. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +514 -3
  140. package/Tests/App/Dashboard/ProductMenuBreadcrumbs.test.tsx +391 -0
  141. package/Tests/App/Dashboard/ScheduledMaintenanceSideMenu.test.tsx +326 -0
  142. package/Tests/App/Dashboard/SideMenuHarness.tsx +187 -0
  143. package/Tests/App/Dashboard/WidgetCatalog.test.ts +6 -1
  144. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +1858 -0
  145. package/Tests/Models/DatabaseModels/DataSourceModelSecrets.test.ts +70 -0
  146. package/Tests/Server/API/AIInvestigationAPI.test.ts +187 -0
  147. package/Tests/Server/API/DashboardPublicDataSourceStrip.test.ts +686 -0
  148. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +585 -823
  149. package/Tests/Server/API/DataSourceAPIRoutes.test.ts +486 -0
  150. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +291 -0
  151. package/Tests/Server/API/UserAuthenticationAPI.test.ts +641 -0
  152. package/Tests/Server/Infrastructure/ClickhouseKeepAliveOptions.test.ts +441 -0
  153. package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +140 -0
  154. package/Tests/Server/Services/AIInsightService.test.ts +266 -11
  155. package/Tests/Server/Services/AIRunAnalysisTldrPersistence.test.ts +160 -0
  156. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +4 -0
  157. package/Tests/Server/Services/AlertMetricResourceAttributes.test.ts +352 -0
  158. package/Tests/Server/Services/DataSourceServiceSettings.test.ts +244 -0
  159. package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +397 -0
  160. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +41 -2
  161. package/Tests/Server/Services/IncidentMetricResourceAttributes.test.ts +408 -0
  162. package/Tests/Server/Services/MonitorStatusServiceDeleteReferenceCleanup.test.ts +351 -0
  163. package/Tests/Server/Services/MonitorStatusServiceValidation.test.ts +171 -0
  164. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +398 -0
  165. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +19 -0
  166. package/Tests/Server/Services/ProjectCallSMSConfigCredentialUniqueness.test.ts +305 -0
  167. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +36 -1
  168. package/Tests/Server/Services/RumSessionPinUniqueViolationRecovery.test.ts +163 -0
  169. package/Tests/Server/Services/UserAuthenticationService.test.ts +973 -0
  170. package/Tests/Server/Types/Database/ObjectIdColumnQuery.test.ts +262 -0
  171. package/Tests/Server/Types/Database/Permissions/TenantPermission.test.ts +358 -0
  172. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +2 -2
  173. package/Tests/Server/Utils/AI/Insights/ExceptionSpikeDetector.test.ts +6 -1
  174. package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +121 -4
  175. package/Tests/Server/Utils/AI/Insights/NewExceptionDetector.test.ts +361 -10
  176. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +292 -0
  177. package/Tests/Server/Utils/AI/InvestigationTldr.test.ts +623 -0
  178. package/Tests/Server/Utils/AI/InvestigationTldrWiring.test.ts +98 -0
  179. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +857 -0
  180. package/Tests/Server/Utils/Dashboard/PublicDashboardViewConfig.test.ts +480 -0
  181. package/Tests/Server/Utils/DataSource/ClickHouseConnector.test.ts +759 -0
  182. package/Tests/Server/Utils/DataSource/ConnectorRegistry.test.ts +37 -0
  183. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +645 -0
  184. package/Tests/Server/Utils/DataSource/ElasticsearchConnector.test.ts +1206 -0
  185. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +616 -0
  186. package/Tests/Server/Utils/DataSource/LokiConnector.test.ts +970 -0
  187. package/Tests/Server/Utils/DataSource/MySqlConnector.test.ts +935 -0
  188. package/Tests/Server/Utils/DataSource/PostgresConnector.test.ts +854 -0
  189. package/Tests/Server/Utils/DataSource/PrometheusConnector.test.ts +881 -0
  190. package/Tests/Server/Utils/DataSource/RestApiConnector.test.ts +1020 -0
  191. package/Tests/Server/Utils/DataSource/SqlQueryGuard.test.ts +425 -0
  192. package/Tests/Server/Utils/DataSource/SqlResultShaper.test.ts +555 -0
  193. package/Tests/Server/Utils/DataSource/SqlServerConnector.test.ts +934 -0
  194. package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +228 -7
  195. package/Tests/Server/Utils/InProcessMemo.test.ts +292 -0
  196. package/Tests/Server/Utils/InstanceHealth/TelemetryIngestion.test.ts +960 -0
  197. package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +103 -0
  198. package/Tests/Server/Utils/Monitor/MonitorMetricResourceAttributes.test.ts +336 -0
  199. package/Tests/Server/Utils/OfflineAssetHygiene.test.ts +521 -0
  200. package/Tests/Server/Utils/ResponseRenderAnalytics.test.ts +143 -0
  201. package/Tests/Server/Utils/SSRFProtection.test.ts +193 -0
  202. package/Tests/Server/Utils/StatusPageSubscriberWebhook.test.ts +101 -0
  203. package/Tests/Server/Utils/TailwindBuildCopy.test.ts +225 -0
  204. package/Tests/Server/Utils/Telemetry/ResourceHeartbeatL1Memo.test.ts +355 -0
  205. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriter.test.ts +128 -0
  206. package/Tests/Server/Utils/Telemetry/TelemetryUtilAttributeKeys.test.ts +381 -0
  207. package/Tests/Server/Utils/Telemetry.test.ts +87 -0
  208. package/Tests/Server/Utils/VendorAssetIntegrity.test.ts +343 -0
  209. package/Tests/Server/Utils/VendorAssets.test.ts +671 -0
  210. package/Tests/Server/Views/OfflineRender.test.ts +297 -0
  211. package/Tests/Types/Dashboard/DataSourceComponentTypes.test.ts +618 -0
  212. package/Tests/Types/DateClickhouseFormat.test.ts +192 -0
  213. package/Tests/Types/Password.test.ts +363 -0
  214. package/Tests/UI/Components/ConfirmModal.test.tsx +7 -0
  215. package/Tests/UI/Components/ErrorBoundary.test.tsx +53 -0
  216. package/Tests/UI/Components/Modal.test.tsx +281 -1
  217. package/Tests/UI/Components/ObjectIdFilterPipeline.test.tsx +396 -0
  218. package/Tests/UI/Components/StatusPage/ResourceGroupNavigator.test.tsx +1147 -0
  219. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +116 -1
  220. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  221. package/Tests/Utils/Analytics.test.ts +23 -0
  222. package/Tests/Utils/Dashboard/Components/DashboardDataSourceComponents.test.ts +640 -0
  223. package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +138 -0
  224. package/Tests/Utils/DataSource/DataSourceValueReducer.test.ts +526 -0
  225. package/Tests/Utils/Metrics/MetricResourceAttributeUtil.test.ts +691 -0
  226. package/Tests/Utils/StatusPage/GroupHierarchyView.test.ts +1452 -0
  227. package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +931 -0
  228. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +288 -0
  229. package/Tests/Utils/Telemetry/IngestionTimestamp.test.ts +170 -0
  230. package/Types/AI/AIInsightEvidence.ts +6 -0
  231. package/Types/Analytics/RevenueEvent.ts +31 -0
  232. package/Types/Dashboard/DashboardComponentType.ts +31 -0
  233. package/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.ts +27 -0
  234. package/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.ts +32 -0
  235. package/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.ts +30 -0
  236. package/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.ts +55 -0
  237. package/Types/DataSource/DataSourceLimits.ts +62 -0
  238. package/Types/DataSource/DataSourceQueryConfig.ts +41 -0
  239. package/Types/DataSource/DataSourceTableResult.ts +38 -0
  240. package/Types/DataSource/DataSourceType.ts +213 -0
  241. package/Types/Date.ts +43 -3
  242. package/Types/Password.ts +64 -0
  243. package/Types/Permission.ts +46 -0
  244. package/Types/UserAuthenticationStatus.ts +34 -0
  245. package/UI/Components/Button/Button.tsx +1 -1
  246. package/UI/Components/ErrorBoundary.tsx +459 -108
  247. package/UI/Components/Icon/Icon.tsx +10 -9
  248. package/UI/Components/Modal/ConfirmModal.tsx +6 -1
  249. package/UI/Components/Modal/Modal.tsx +267 -35
  250. package/UI/Components/Modal/ModalFooter.tsx +6 -1
  251. package/UI/Components/MoreMenu/MoreMenu.tsx +19 -4
  252. package/UI/Components/MoreMenu/MoreMenuItem.tsx +6 -1
  253. package/UI/Components/StatusPage/ResourceGrid.tsx +314 -0
  254. package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +808 -0
  255. package/UI/Components/StatusPage/ResourceList.tsx +570 -0
  256. package/UI/Styles/Theme.css +18 -0
  257. package/UI/Utils/API/RequestOptions.ts +7 -0
  258. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +1 -0
  259. package/UI/Utils/ModelAPI/ModelAPI.ts +1 -0
  260. package/UI/Utils/TestDataSource.ts +61 -0
  261. package/UI/esbuild-config.js +45 -0
  262. package/Utils/Analytics.ts +15 -0
  263. package/Utils/Dashboard/Components/DashboardDataSourceChartComponent.ts +88 -0
  264. package/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.ts +123 -0
  265. package/Utils/Dashboard/Components/DashboardDataSourceShared.ts +16 -0
  266. package/Utils/Dashboard/Components/DashboardDataSourceTableComponent.ts +72 -0
  267. package/Utils/Dashboard/Components/DashboardDataSourceValueComponent.ts +126 -0
  268. package/Utils/Dashboard/Components/Index.ts +28 -0
  269. package/Utils/DataSource/DataSourceQueryText.ts +94 -0
  270. package/Utils/DataSource/DataSourceValueReducer.ts +156 -0
  271. package/Utils/Metrics/MetricResourceAttributeUtil.ts +380 -0
  272. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +8 -6
  273. package/Utils/StatusPage/GroupHierarchyView.ts +931 -0
  274. package/Utils/StatusPage/ResourceExplorer.ts +853 -0
  275. package/build/dist/Models/DatabaseModels/AIRun.js +34 -0
  276. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  277. package/build/dist/Models/DatabaseModels/DataSource.js +774 -0
  278. package/build/dist/Models/DatabaseModels/DataSource.js.map +1 -0
  279. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  280. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  281. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +14 -4
  282. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
  283. package/build/dist/Models/DatabaseModels/User.js +2 -0
  284. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  285. package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -0
  286. package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
  287. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +2 -0
  288. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  289. package/build/dist/Models/DatabaseModels/UserSession.js +2 -0
  290. package/build/dist/Models/DatabaseModels/UserSession.js.map +1 -1
  291. package/build/dist/Models/DatabaseModels/UserTotpAuth.js +6 -4
  292. package/build/dist/Models/DatabaseModels/UserTotpAuth.js.map +1 -1
  293. package/build/dist/Models/DatabaseModels/UserWebAuthn.js +5 -3
  294. package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -1
  295. package/build/dist/Server/API/AIInsightAPI.js +34 -4
  296. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  297. package/build/dist/Server/API/AIInvestigationAPI.js +23 -0
  298. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  299. package/build/dist/Server/API/DashboardAPI.js +119 -433
  300. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  301. package/build/dist/Server/API/DataSourceAPI.js +173 -0
  302. package/build/dist/Server/API/DataSourceAPI.js.map +1 -0
  303. package/build/dist/Server/API/StatusPageAPI.js +11 -1
  304. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  305. package/build/dist/Server/API/UserAPI.js +94 -2
  306. package/build/dist/Server/API/UserAPI.js.map +1 -1
  307. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +49 -0
  308. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  309. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js +20 -0
  310. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786303472848-AddDataSourceTable.js.map +1 -0
  311. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js +19 -0
  312. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786600000000-AddInvestigationAnalysisTldr.js.map +1 -0
  313. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js +64 -0
  314. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786700000000-DropProjectCallSMSConfigCredentialUniques.js.map +1 -0
  315. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  316. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  317. package/build/dist/Server/Infrastructure/Queue.js +27 -0
  318. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  319. package/build/dist/Server/Infrastructure/QueueWorker.js +13 -0
  320. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  321. package/build/dist/Server/Middleware/TelemetryIngest.js +8 -3
  322. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  323. package/build/dist/Server/Services/AIInsightService.js +110 -10
  324. package/build/dist/Server/Services/AIInsightService.js.map +1 -1
  325. package/build/dist/Server/Services/AIRunService.js +34 -0
  326. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  327. package/build/dist/Server/Services/AIService.js +16 -2
  328. package/build/dist/Server/Services/AIService.js.map +1 -1
  329. package/build/dist/Server/Services/AlertService.js +28 -35
  330. package/build/dist/Server/Services/AlertService.js.map +1 -1
  331. package/build/dist/Server/Services/AnalyticsDatabaseService.js +8 -4
  332. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  333. package/build/dist/Server/Services/DataSourceService.js +159 -0
  334. package/build/dist/Server/Services/DataSourceService.js.map +1 -0
  335. package/build/dist/Server/Services/HostService.js +74 -0
  336. package/build/dist/Server/Services/HostService.js.map +1 -1
  337. package/build/dist/Server/Services/IncidentService.js +35 -24
  338. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  339. package/build/dist/Server/Services/Index.js +2 -0
  340. package/build/dist/Server/Services/Index.js.map +1 -1
  341. package/build/dist/Server/Services/MonitorService.js +45 -0
  342. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  343. package/build/dist/Server/Services/MonitorStatusService.js +129 -0
  344. package/build/dist/Server/Services/MonitorStatusService.js.map +1 -1
  345. package/build/dist/Server/Services/OpenTelemetryIngestService.js +222 -159
  346. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  347. package/build/dist/Server/Services/RumSessionPinService.js +7 -15
  348. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  349. package/build/dist/Server/Services/StatusPageSubscriberService.js +10 -0
  350. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  351. package/build/dist/Server/Services/UserService.js +241 -10
  352. package/build/dist/Server/Services/UserService.js.map +1 -1
  353. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +6 -0
  354. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  355. package/build/dist/Server/Types/Database/Permissions/DeletePermission.js +1 -0
  356. package/build/dist/Server/Types/Database/Permissions/DeletePermission.js.map +1 -1
  357. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +2 -0
  358. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
  359. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +68 -12
  360. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
  361. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +2 -2
  362. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  363. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +68 -8
  364. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  365. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +1 -0
  366. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  367. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +1 -0
  368. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  369. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js +97 -0
  370. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionIdentity.js.map +1 -0
  371. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +17 -15
  372. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  373. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +178 -54
  374. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  375. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js +65 -16
  376. package/build/dist/Server/Utils/AI/SRE/Insights/InsightStore.js.map +1 -1
  377. package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js +303 -0
  378. package/build/dist/Server/Utils/AI/SRE/InvestigationTldr.js.map +1 -0
  379. package/build/dist/Server/Utils/AnalyticsDatabase/InsertDedupContext.js.map +1 -1
  380. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +1261 -0
  381. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -0
  382. package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js +47 -0
  383. package/build/dist/Server/Utils/Dashboard/PublicDashboardViewConfig.js.map +1 -0
  384. package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js +42 -0
  385. package/build/dist/Server/Utils/DataSource/ConnectorRegistry.js.map +1 -0
  386. package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js +187 -0
  387. package/build/dist/Server/Utils/DataSource/Connectors/ClickHouseConnector.js.map +1 -0
  388. package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js +493 -0
  389. package/build/dist/Server/Utils/DataSource/Connectors/ElasticsearchConnector.js.map +1 -0
  390. package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js +399 -0
  391. package/build/dist/Server/Utils/DataSource/Connectors/LokiConnector.js.map +1 -0
  392. package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js +195 -0
  393. package/build/dist/Server/Utils/DataSource/Connectors/MySqlConnector.js.map +1 -0
  394. package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js +149 -0
  395. package/build/dist/Server/Utils/DataSource/Connectors/PostgresConnector.js.map +1 -0
  396. package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js +362 -0
  397. package/build/dist/Server/Utils/DataSource/Connectors/PrometheusConnector.js.map +1 -0
  398. package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js +342 -0
  399. package/build/dist/Server/Utils/DataSource/Connectors/RestApiConnector.js.map +1 -0
  400. package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js +186 -0
  401. package/build/dist/Server/Utils/DataSource/Connectors/SqlServerConnector.js.map +1 -0
  402. package/build/dist/Server/Utils/DataSource/EgressGuard.js +305 -0
  403. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -0
  404. package/build/dist/Server/Utils/DataSource/HttpFetch.js +134 -0
  405. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -0
  406. package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js +331 -0
  407. package/build/dist/Server/Utils/DataSource/SqlQueryGuard.js.map +1 -0
  408. package/build/dist/Server/Utils/DataSource/SqlResultShaper.js +280 -0
  409. package/build/dist/Server/Utils/DataSource/SqlResultShaper.js.map +1 -0
  410. package/build/dist/Server/Utils/DataSource/Types.js +2 -0
  411. package/build/dist/Server/Utils/DataSource/Types.js.map +1 -0
  412. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +103 -9
  413. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -1
  414. package/build/dist/Server/Utils/InProcessMemo.js +113 -0
  415. package/build/dist/Server/Utils/InProcessMemo.js.map +1 -0
  416. package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js +406 -0
  417. package/build/dist/Server/Utils/InstanceHealth/TelemetryIngestion.js.map +1 -0
  418. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +34 -0
  419. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  420. package/build/dist/Server/Utils/Monitor/MonitorResource.js +14 -0
  421. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  422. package/build/dist/Server/Utils/Response.js +9 -1
  423. package/build/dist/Server/Utils/Response.js.map +1 -1
  424. package/build/dist/Server/Utils/SSRFProtection.js +192 -0
  425. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -0
  426. package/build/dist/Server/Utils/StartServer.js +7 -0
  427. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  428. package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js +24 -0
  429. package/build/dist/Server/Utils/StatusPageSubscriberWebhook.js.map +1 -1
  430. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +25 -11
  431. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  432. package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js +32 -0
  433. package/build/dist/Server/Utils/Telemetry/IngestionTimestamp.js.map +1 -0
  434. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +92 -5
  435. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -1
  436. package/build/dist/Server/Utils/Telemetry/Telemetry.js +92 -6
  437. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  438. package/build/dist/Server/Utils/Telemetry.js +93 -6
  439. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  440. package/build/dist/Server/Utils/VendorAssets.js +121 -0
  441. package/build/dist/Server/Utils/VendorAssets.js.map +1 -0
  442. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +25 -4
  443. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  444. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +5 -0
  445. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  446. package/build/dist/Types/Analytics/RevenueEvent.js +26 -0
  447. package/build/dist/Types/Analytics/RevenueEvent.js.map +1 -0
  448. package/build/dist/Types/Dashboard/DashboardComponentType.js +27 -0
  449. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  450. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js +2 -0
  451. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceChartComponent.js.map +1 -0
  452. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js +2 -0
  453. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceGaugeComponent.js.map +1 -0
  454. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js +2 -0
  455. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceTableComponent.js.map +1 -0
  456. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js +16 -0
  457. package/build/dist/Types/Dashboard/DashboardComponents/DashboardDataSourceValueComponent.js.map +1 -0
  458. package/build/dist/Types/DataSource/DataSourceLimits.js +47 -0
  459. package/build/dist/Types/DataSource/DataSourceLimits.js.map +1 -0
  460. package/build/dist/Types/DataSource/DataSourceQueryConfig.js +10 -0
  461. package/build/dist/Types/DataSource/DataSourceQueryConfig.js.map +1 -0
  462. package/build/dist/Types/DataSource/DataSourceTableResult.js +14 -0
  463. package/build/dist/Types/DataSource/DataSourceTableResult.js.map +1 -0
  464. package/build/dist/Types/DataSource/DataSourceType.js +183 -0
  465. package/build/dist/Types/DataSource/DataSourceType.js.map +1 -0
  466. package/build/dist/Types/Date.js +38 -3
  467. package/build/dist/Types/Date.js.map +1 -1
  468. package/build/dist/Types/Password.js +56 -0
  469. package/build/dist/Types/Password.js.map +1 -0
  470. package/build/dist/Types/Permission.js +42 -0
  471. package/build/dist/Types/Permission.js.map +1 -1
  472. package/build/dist/Types/UserAuthenticationStatus.js +2 -0
  473. package/build/dist/Types/UserAuthenticationStatus.js.map +1 -0
  474. package/build/dist/UI/Components/ErrorBoundary.js +388 -72
  475. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  476. package/build/dist/UI/Components/Icon/Icon.js +10 -4
  477. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  478. package/build/dist/UI/Components/Modal/ConfirmModal.js +1 -1
  479. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  480. package/build/dist/UI/Components/Modal/Modal.js +178 -19
  481. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  482. package/build/dist/UI/Components/Modal/ModalFooter.js +3 -1
  483. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  484. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +9 -6
  485. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  486. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +7 -1
  487. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  488. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +119 -0
  489. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -0
  490. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +354 -0
  491. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -0
  492. package/build/dist/UI/Components/StatusPage/ResourceList.js +203 -0
  493. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -0
  494. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +1 -6
  495. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  496. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +3 -8
  497. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  498. package/build/dist/UI/Utils/TestDataSource.js +39 -0
  499. package/build/dist/UI/Utils/TestDataSource.js.map +1 -0
  500. package/build/dist/Utils/Analytics.js +4 -0
  501. package/build/dist/Utils/Analytics.js.map +1 -1
  502. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js +79 -0
  503. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceChartComponent.js.map +1 -0
  504. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js +111 -0
  505. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceGaugeComponent.js.map +1 -0
  506. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js +15 -0
  507. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceShared.js.map +1 -0
  508. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js +62 -0
  509. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceTableComponent.js.map +1 -0
  510. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js +112 -0
  511. package/build/dist/Utils/Dashboard/Components/DashboardDataSourceValueComponent.js.map +1 -0
  512. package/build/dist/Utils/Dashboard/Components/Index.js +16 -0
  513. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  514. package/build/dist/Utils/DataSource/DataSourceQueryText.js +64 -0
  515. package/build/dist/Utils/DataSource/DataSourceQueryText.js.map +1 -0
  516. package/build/dist/Utils/DataSource/DataSourceValueReducer.js +124 -0
  517. package/build/dist/Utils/DataSource/DataSourceValueReducer.js.map +1 -0
  518. package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js +281 -0
  519. package/build/dist/Utils/Metrics/MetricResourceAttributeUtil.js.map +1 -0
  520. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +8 -6
  521. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -1
  522. package/build/dist/Utils/StatusPage/GroupHierarchyView.js +560 -0
  523. package/build/dist/Utils/StatusPage/GroupHierarchyView.js.map +1 -0
  524. package/build/dist/Utils/StatusPage/ResourceExplorer.js +519 -0
  525. package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -0
  526. package/jest.config.json +1 -0
  527. package/package.json +5 -1
  528. package/tsconfig.json +12 -10
@@ -0,0 +1,355 @@
1
+ import GlobalCache from "../../../../Server/Infrastructure/GlobalCache";
2
+ import ResourceHeartbeat from "../../../../Server/Utils/Telemetry/ResourceHeartbeat";
3
+ import SingleFlight from "../../../../Server/Utils/SingleFlight";
4
+ import ObjectID from "../../../../Types/ObjectID";
5
+ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
6
+
7
+ /*
8
+ * The time-based L1 in front of ResourceHeartbeat's Redis gate cascade.
9
+ *
10
+ * SingleFlight already collapses CONCURRENT duplicate heartbeats, but every
11
+ * SEQUENTIAL batch — the next job for the same host a second later — still
12
+ * paid 1-3 serialized Redis round trips (liveness SET NX, fingerprint
13
+ * compare-and-claim, rate-limit SET NX) to learn "nothing to do". The memo
14
+ * remembers a SETTLED heartbeat for (resource, fingerprint) for
15
+ * min(60s, liveness window) so those batches cost zero network round trips.
16
+ *
17
+ * What is pinned here, in order of importance:
18
+ *
19
+ * 1. A repeat identical heartbeat inside the window touches NEITHER Redis
20
+ * nor Postgres — the whole point of the change.
21
+ * 2. The memo expires with the window: after it, Redis is consulted again.
22
+ * 3. A CHANGED fingerprint bypasses the memo, so the change-promptness
23
+ * contract of the compare-and-claim gate is untouched.
24
+ * 4. Outcomes that must retry are never memoized: a failed metadata write,
25
+ * a lock-skipped enrichment write, and any outcome where a gate probe
26
+ * threw (a Redis outage must keep failing open per batch — memoizing
27
+ * an outage outcome would suppress liveness for a healthy resource).
28
+ *
29
+ * The gates are modelled faithfully (SET NX only succeeds on an absent key,
30
+ * compare-and-claim only on a differing value) — same discipline as the
31
+ * neighbouring heartbeat suites, and for the same reason: a stubbed-constant
32
+ * gate would let this suite agree with a memo that breaks the throttle.
33
+ */
34
+
35
+ const RESOURCE_ID: ObjectID = ObjectID.generate();
36
+ const NAMESPACE: string = "heartbeat-memo-test-last-seen";
37
+ const WINDOW_SECONDS: number = 60;
38
+
39
+ type WriteCall = { id: ObjectID; data: Record<string, unknown> };
40
+
41
+ let cache: Map<string, string>;
42
+ let writes: Array<WriteCall>;
43
+ let writeLands: boolean;
44
+ let writeThrows: boolean;
45
+ let nowMs: number;
46
+
47
+ /** The service seam ResourceHeartbeat writes through, recording instead. */
48
+ /* eslint-disable @typescript-eslint/no-explicit-any */
49
+ const fakeService: any = {
50
+ updateColumnsByIdIfUnlockedWithoutHooks: async (input: {
51
+ id: ObjectID;
52
+ data: unknown;
53
+ }): Promise<boolean> => {
54
+ writes.push({
55
+ id: input.id,
56
+ data: { ...(input.data as Record<string, unknown>) },
57
+ });
58
+ if (
59
+ writeThrows &&
60
+ Object.keys(writes[writes.length - 1]!.data).length > 1
61
+ ) {
62
+ throw new Error("value too long for type character varying(100)");
63
+ }
64
+ return writeLands;
65
+ },
66
+ };
67
+ /* eslint-enable @typescript-eslint/no-explicit-any */
68
+
69
+ function gateCallCount(): number {
70
+ return (
71
+ (GlobalCache.setStringIfNotExists as jest.Mock).mock.calls.length +
72
+ (GlobalCache.setStringIfChanged as jest.Mock).mock.calls.length
73
+ );
74
+ }
75
+
76
+ async function heartbeat(input?: {
77
+ fingerprint?: string;
78
+ metadata?: Record<string, unknown>;
79
+ throttleInSeconds?: number;
80
+ }): Promise<void> {
81
+ await ResourceHeartbeat.write({
82
+ service: fakeService,
83
+ id: RESOURCE_ID,
84
+ cacheNamespace: NAMESPACE,
85
+ throttleInSeconds: input?.throttleInSeconds ?? WINDOW_SECONDS,
86
+ liveness: { lastSeenAt: "now" } as never,
87
+ metadata: (input?.metadata ?? undefined) as never,
88
+ fingerprint: input?.fingerprint ?? "fp-default",
89
+ describe: `test resource ${RESOURCE_ID.toString()}`,
90
+ });
91
+ }
92
+
93
+ describe("ResourceHeartbeat recent-heartbeat L1 memo", () => {
94
+ beforeEach(() => {
95
+ cache = new Map<string, string>();
96
+ writes = [];
97
+ writeLands = true;
98
+ writeThrows = false;
99
+ nowMs = 1_700_000_000_000;
100
+
101
+ SingleFlight.clear();
102
+ ResourceHeartbeat.clearRecentHeartbeatMemo();
103
+
104
+ jest.spyOn(Date, "now").mockImplementation(() => {
105
+ return nowMs;
106
+ });
107
+
108
+ jest
109
+ .spyOn(GlobalCache, "setStringIfNotExists")
110
+ .mockImplementation(
111
+ async (namespace: string, key: string, value: string) => {
112
+ const full: string = `${namespace}:${key}`;
113
+ if (cache.has(full)) {
114
+ return false;
115
+ }
116
+ cache.set(full, value);
117
+ return true;
118
+ },
119
+ );
120
+ jest
121
+ .spyOn(GlobalCache, "setStringIfChanged")
122
+ .mockImplementation(
123
+ async (namespace: string, key: string, value: string) => {
124
+ const full: string = `${namespace}:${key}`;
125
+ if (cache.get(full) === value) {
126
+ return false;
127
+ }
128
+ cache.set(full, value);
129
+ return true;
130
+ },
131
+ );
132
+ jest
133
+ .spyOn(GlobalCache, "deleteKey")
134
+ .mockImplementation(async (namespace: string, key: string) => {
135
+ cache.delete(`${namespace}:${key}`);
136
+ });
137
+ });
138
+
139
+ afterEach(() => {
140
+ jest.restoreAllMocks();
141
+ SingleFlight.clear();
142
+ ResourceHeartbeat.clearRecentHeartbeatMemo();
143
+ });
144
+
145
+ describe("the settled-heartbeat skip", () => {
146
+ test("a repeat identical heartbeat touches neither Redis nor Postgres", async () => {
147
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
148
+
149
+ const gatesAfterFirst: number = gateCallCount();
150
+ const writesAfterFirst: number = writes.length;
151
+ expect(writesAfterFirst).toBe(1);
152
+
153
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
154
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
155
+
156
+ expect(gateCallCount()).toBe(gatesAfterFirst);
157
+ expect(writes).toHaveLength(writesAfterFirst);
158
+ });
159
+
160
+ test("a liveness-only heartbeat (no metadata) is memoized too", async () => {
161
+ await heartbeat();
162
+ const gatesAfterFirst: number = gateCallCount();
163
+
164
+ await heartbeat();
165
+
166
+ expect(gateCallCount()).toBe(gatesAfterFirst);
167
+ expect(writes).toHaveLength(1);
168
+ });
169
+
170
+ test("a refused window is memoized after ONE probe — the steady state costs one round trip per window", async () => {
171
+ /*
172
+ * Another pod already holds the liveness gate and the fingerprint is
173
+ * already stored: this pod's first batch probes and is refused, and
174
+ * every later batch in the window must not re-ask.
175
+ */
176
+ cache.set(`${NAMESPACE}:${RESOURCE_ID.toString()}`, "1");
177
+ cache.set(`${NAMESPACE}-fingerprint:${RESOURCE_ID.toString()}`, "fp-a");
178
+
179
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
180
+ const gatesAfterFirst: number = gateCallCount();
181
+ expect(writes).toHaveLength(0);
182
+
183
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
184
+
185
+ expect(gateCallCount()).toBe(gatesAfterFirst);
186
+ expect(writes).toHaveLength(0);
187
+ });
188
+
189
+ test("different resources do not share an entry", async () => {
190
+ await heartbeat();
191
+
192
+ const otherId: ObjectID = ObjectID.generate();
193
+ await ResourceHeartbeat.write({
194
+ service: fakeService,
195
+ id: otherId,
196
+ cacheNamespace: NAMESPACE,
197
+ throttleInSeconds: WINDOW_SECONDS,
198
+ liveness: { lastSeenAt: "now" } as never,
199
+ metadata: undefined as never,
200
+ fingerprint: "fp-default",
201
+ describe: `test resource ${otherId.toString()}`,
202
+ });
203
+
204
+ // Both wrote — the second resource was not suppressed by the first's memo.
205
+ expect(writes).toHaveLength(2);
206
+ });
207
+ });
208
+
209
+ describe("memo lifetime", () => {
210
+ test("expires with the window: Redis is consulted again afterwards", async () => {
211
+ await heartbeat();
212
+ const gatesAfterFirst: number = gateCallCount();
213
+
214
+ nowMs += WINDOW_SECONDS * 1000 + 1;
215
+ await heartbeat();
216
+
217
+ expect(gateCallCount()).toBeGreaterThan(gatesAfterFirst);
218
+ });
219
+
220
+ test("is capped at the caller's own window when that is shorter than 60s", async () => {
221
+ await heartbeat({ throttleInSeconds: 10 });
222
+ const gatesAfterFirst: number = gateCallCount();
223
+
224
+ // 11s later the 10s window may have reopened; the memo must not outlive it.
225
+ nowMs += 11 * 1000;
226
+ await heartbeat({ throttleInSeconds: 10 });
227
+
228
+ expect(gateCallCount()).toBeGreaterThan(gatesAfterFirst);
229
+ });
230
+
231
+ test("never outlives the pre-jitter Redis window it fronts", async () => {
232
+ /*
233
+ * Inside the pre-jitter window the Redis liveness key cannot have
234
+ * expired (its jittered TTL >= the window), so a skipped probe is
235
+ * outcome-identical to a refused probe. Just before the boundary the
236
+ * memo may still answer; the write count must therefore stay at one
237
+ * either way.
238
+ */
239
+ await heartbeat();
240
+ nowMs += (WINDOW_SECONDS - 1) * 1000;
241
+ await heartbeat();
242
+
243
+ expect(writes).toHaveLength(1);
244
+ });
245
+ });
246
+
247
+ describe("change promptness", () => {
248
+ test("a changed fingerprint bypasses the memo and reaches Redis immediately", async () => {
249
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
250
+ const gatesAfterFirst: number = gateCallCount();
251
+
252
+ await heartbeat({ metadata: { osType: "windows" }, fingerprint: "fp-b" });
253
+
254
+ expect(gateCallCount()).toBeGreaterThan(gatesAfterFirst);
255
+ });
256
+
257
+ test("the changed payload still lands in the next window, exactly as before the memo", async () => {
258
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
259
+
260
+ // Both windows reopen (as their Redis TTLs would).
261
+ cache.delete(`${NAMESPACE}:${RESOURCE_ID.toString()}`);
262
+ cache.delete(`${NAMESPACE}-write-window:${RESOURCE_ID.toString()}`);
263
+
264
+ await heartbeat({ metadata: { osType: "windows" }, fingerprint: "fp-b" });
265
+
266
+ expect(writes).toHaveLength(2);
267
+ expect(writes[1]!.data["osType"]).toBe("windows");
268
+ });
269
+ });
270
+
271
+ describe("outcomes that must retry are not memoized", () => {
272
+ test("a failed metadata write retries on the very next batch", async () => {
273
+ writeThrows = true;
274
+
275
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
276
+ // Enriched attempt + liveness-only fallback.
277
+ expect(writes).toHaveLength(2);
278
+
279
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
280
+
281
+ // Retried — not silently swallowed by the memo.
282
+ expect(writes).toHaveLength(4);
283
+ });
284
+
285
+ test("a lock-skipped enrichment write retries on the very next batch", async () => {
286
+ writeLands = false;
287
+
288
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
289
+ expect(writes).toHaveLength(1);
290
+
291
+ writeLands = true;
292
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
293
+
294
+ expect(writes).toHaveLength(2);
295
+ });
296
+
297
+ test("a liveness-gate outage keeps failing open on every batch", async () => {
298
+ /*
299
+ * If an outage outcome were memoized, one failed probe would suppress
300
+ * heartbeats for a healthy resource for a full memo TTL — the exact
301
+ * "shown disconnected while telemetry keeps arriving" failure mode
302
+ * the fail-open policy exists to prevent.
303
+ */
304
+ jest
305
+ .spyOn(GlobalCache, "setStringIfNotExists")
306
+ .mockRejectedValue(new Error("redis down"));
307
+
308
+ await heartbeat();
309
+ await heartbeat();
310
+ await heartbeat();
311
+
312
+ expect(writes).toHaveLength(3);
313
+ });
314
+
315
+ test("an enrichment-gate outage is not memoized — enrichment recovers with Redis", async () => {
316
+ jest
317
+ .spyOn(GlobalCache, "setStringIfChanged")
318
+ .mockRejectedValue(new Error("redis down"));
319
+
320
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
321
+ // Liveness-only write; enrichment failed closed.
322
+ expect(writes).toHaveLength(1);
323
+ expect(writes[0]!.data["osType"]).toBeUndefined();
324
+
325
+ // Redis comes back; the same batch content must now enrich promptly.
326
+ (GlobalCache.setStringIfChanged as jest.Mock).mockImplementation(
327
+ async (namespace: string, key: string, value: string) => {
328
+ const full: string = `${namespace}:${key}`;
329
+ if (cache.get(full) === value) {
330
+ return false;
331
+ }
332
+ cache.set(full, value);
333
+ return true;
334
+ },
335
+ );
336
+
337
+ await heartbeat({ metadata: { osType: "linux" }, fingerprint: "fp-a" });
338
+
339
+ expect(writes).toHaveLength(2);
340
+ expect(writes[1]!.data["osType"]).toBe("linux");
341
+ });
342
+ });
343
+
344
+ describe("clearRecentHeartbeatMemo", () => {
345
+ test("drops the memo so the next call probes again — the test-only escape hatch works", async () => {
346
+ await heartbeat();
347
+ const gatesAfterFirst: number = gateCallCount();
348
+
349
+ ResourceHeartbeat.clearRecentHeartbeatMemo();
350
+ await heartbeat();
351
+
352
+ expect(gateCallCount()).toBeGreaterThan(gatesAfterFirst);
353
+ });
354
+ });
355
+ });
@@ -828,6 +828,134 @@ describe("TelemetryFanInWriter", () => {
828
828
  expect(target.insertJsonRows).toHaveBeenCalledTimes(1);
829
829
  expect(callOptions(target, 0).clickhouseSettings).toBe(settingsFirst);
830
830
  });
831
+
832
+ /*
833
+ * The production shape after the batched-inserts change: one table can
834
+ * receive tokened submissions (low-volume signals like syslog, still
835
+ * inside runWithInsertDedup) and untokened ones (traces/logs/metrics)
836
+ * in the same flush window. Tokened submissions must keep per-job
837
+ * statement granularity; the untokened remainder must collapse into
838
+ * one minted-token statement.
839
+ */
840
+ test("mixed tokened/untokened batch: tokened submissions insert individually under their tokens, the untokened remainder merges under one minted token", async () => {
841
+ const target: TestTarget = makeTarget();
842
+ const writer: TelemetryFanInWriter = new TelemetryFanInWriter(
843
+ makeOptions({ maxBatchRows: 8, maxWaitMs: 60_000 }),
844
+ );
845
+
846
+ const tokenedFirst: FanInSubmitResult = await runWithInsertDedup(
847
+ "job-a",
848
+ () => {
849
+ return writer.submit(target, makeRows(2));
850
+ },
851
+ );
852
+ /*
853
+ * TWO untokened submissions, not one: merging a single-element group is
854
+ * indistinguishable from inserting it alone, so one would make the
855
+ * "merges" half of this assertion vacuous — a regression to
856
+ * one-statement-per-submission would still produce the same call count.
857
+ */
858
+ const untokenedFirst: FanInSubmitResult = await writer.submit(
859
+ target,
860
+ makeRows(2, 2),
861
+ );
862
+ const untokenedSecond: FanInSubmitResult = await writer.submit(
863
+ target,
864
+ makeRows(2, 4),
865
+ );
866
+ // Reaching maxBatchRows (8) cuts and dispatches the batch.
867
+ const tokenedSecond: FanInSubmitResult = await runWithInsertDedup(
868
+ "job-b",
869
+ () => {
870
+ return writer.submit(target, makeRows(2, 6));
871
+ },
872
+ );
873
+
874
+ await Promise.all([
875
+ tokenedFirst.flushed,
876
+ untokenedFirst.flushed,
877
+ untokenedSecond.flushed,
878
+ tokenedSecond.flushed,
879
+ ]);
880
+
881
+ /*
882
+ * Exactly three statements for four submissions: each tokened
883
+ * submission alone under its deterministic per-job token (in batch
884
+ * order), then BOTH untokened submissions collapsed into one statement
885
+ * under a single minted fanin: token.
886
+ */
887
+ expect(target.insertJsonRows).toHaveBeenCalledTimes(3);
888
+
889
+ expect(callOptions(target, 0).dedupToken).toBe("job-a:TestTable:0");
890
+ expect(rowSeqs(callRows(target, 0))).toEqual([0, 1]);
891
+
892
+ expect(callOptions(target, 1).dedupToken).toBe("job-b:TestTable:0");
893
+ expect(rowSeqs(callRows(target, 1))).toEqual([6, 7]);
894
+
895
+ expect(callOptions(target, 2).dedupToken).toMatch(/^fanin:TestTable:/);
896
+ expect(rowSeqs(callRows(target, 2))).toEqual([2, 3, 4, 5]);
897
+ });
898
+
899
+ test("mixed batch failure isolation: the merged untokened statement failing rejects ALL its submissions with one shared error; tokened ones in the same batch still succeed", async () => {
900
+ const target: TestTarget = makeTarget({
901
+ impl: async (
902
+ _rows: Array<JSONObject>,
903
+ options?: InsertRowsOptions,
904
+ ): Promise<void> => {
905
+ if (options?.dedupToken?.startsWith("fanin:")) {
906
+ // Non-retryable: plain error with no recognized code/message.
907
+ throw new Error("merged statement rejected");
908
+ }
909
+ },
910
+ });
911
+ const writer: TelemetryFanInWriter = new TelemetryFanInWriter(
912
+ makeOptions({ maxBatchRows: 6, maxWaitMs: 60_000 }),
913
+ );
914
+
915
+ const tokened: FanInSubmitResult = await runWithInsertDedup(
916
+ "job-a",
917
+ () => {
918
+ return writer.submit(target, makeRows(2));
919
+ },
920
+ );
921
+ const untokenedFirst: FanInSubmitResult = await writer.submit(
922
+ target,
923
+ makeRows(2, 2),
924
+ );
925
+ const untokenedSecond: FanInSubmitResult = await writer.submit(
926
+ target,
927
+ makeRows(2, 4),
928
+ );
929
+
930
+ // The tokened submission's ack resolves even though its batch-mate failed.
931
+ await tokened.flushed;
932
+
933
+ const errFirst: Error = await captureRejection(untokenedFirst.flushed);
934
+ const errSecond: Error = await captureRejection(untokenedSecond.flushed);
935
+
936
+ expect(errFirst).toBeInstanceOf(FanInInsertError);
937
+ expect(errFirst.message).toContain("merged statement rejected");
938
+ expect(errFirst.message).toContain("after 1 attempt(s)");
939
+ /*
940
+ * The SAME error instance reaches both untokened acks — that identity
941
+ * is what proves they shared one merged statement rather than each
942
+ * failing its own.
943
+ */
944
+ expect(errSecond).toBe(errFirst);
945
+
946
+ // Two statements: the tokened one (ok) and the merged untokened one (failed).
947
+ expect(target.insertJsonRows).toHaveBeenCalledTimes(2);
948
+ expect(callOptions(target, 0).dedupToken).toBe("job-a:TestTable:0");
949
+ expect(callOptions(target, 1).dedupToken).toMatch(/^fanin:TestTable:/);
950
+ expect(rowSeqs(callRows(target, 1))).toEqual([2, 3, 4, 5]);
951
+
952
+ // Failure still drains the writer's accounting.
953
+ expect(writer.getStats()).toEqual({
954
+ bufferedRows: 0,
955
+ pendingRows: 0,
956
+ activeInserts: 0,
957
+ });
958
+ });
831
959
  });
832
960
  });
833
961