@oneuptime/common 12.0.3 → 12.0.5

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 (516) hide show
  1. package/Models/DatabaseModels/AIRun.ts +38 -1
  2. package/Models/DatabaseModels/AlertFeed.ts +30 -0
  3. package/Models/DatabaseModels/CephCluster.ts +14 -0
  4. package/Models/DatabaseModels/CodeRepository.ts +14 -6
  5. package/Models/DatabaseModels/Dashboard.ts +28 -0
  6. package/Models/DatabaseModels/DockerHost.ts +14 -0
  7. package/Models/DatabaseModels/GlobalOidcProject.ts +18 -0
  8. package/Models/DatabaseModels/GlobalSsoProject.ts +18 -0
  9. package/Models/DatabaseModels/Incident.ts +2 -0
  10. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  11. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  12. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  13. package/Models/DatabaseModels/IncidentFeed.ts +30 -0
  14. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  15. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  16. package/Models/DatabaseModels/IoTFleet.ts +14 -0
  17. package/Models/DatabaseModels/KubernetesCluster.ts +14 -0
  18. package/Models/DatabaseModels/LogSavedView.ts +33 -0
  19. package/Models/DatabaseModels/NetworkDevice.ts +14 -0
  20. package/Models/DatabaseModels/NetworkInterface.ts +18 -0
  21. package/Models/DatabaseModels/Project.ts +247 -11
  22. package/Models/DatabaseModels/ProxmoxCluster.ts +14 -0
  23. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  24. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  25. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  26. package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +4 -4
  27. package/Models/DatabaseModels/Service.ts +30 -0
  28. package/Models/DatabaseModels/StatusPage.ts +28 -0
  29. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  30. package/Models/DatabaseModels/StatusPagePrivateUser.ts +30 -0
  31. package/Models/DatabaseModels/User.ts +30 -0
  32. package/Server/API/AIAgentDataAPI.ts +75 -55
  33. package/Server/API/AIInvestigationAPI.ts +175 -17
  34. package/Server/API/DashboardAPI.ts +429 -22
  35. package/Server/API/GitHubAPI.ts +119 -283
  36. package/Server/API/StatusPageAPI.ts +38 -19
  37. package/Server/API/UserAPI.ts +263 -1
  38. package/Server/EnvironmentConfig.ts +23 -3
  39. package/Server/Infrastructure/ClickhouseConfig.ts +15 -1
  40. package/Server/Infrastructure/ClickhouseDatabase.ts +1 -1
  41. package/Server/Infrastructure/GlobalCache.ts +37 -0
  42. package/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.ts +21 -0
  43. package/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.ts +68 -0
  44. package/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.ts +27 -0
  45. package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +100 -0
  46. package/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.ts +89 -0
  47. package/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.ts +27 -0
  48. package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +214 -0
  49. package/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.ts +69 -0
  50. package/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.ts +40 -0
  51. package/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.ts +26 -0
  52. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
  53. package/Server/Services/AIRunService.ts +78 -10
  54. package/Server/Services/AIService.ts +94 -22
  55. package/Server/Services/AlertFeedService.ts +5 -0
  56. package/Server/Services/AnalyticsDatabaseService.ts +101 -1
  57. package/Server/Services/CodeRepositoryService.ts +105 -2
  58. package/Server/Services/DatabaseService.ts +227 -3
  59. package/Server/Services/IncidentFeedService.ts +5 -0
  60. package/Server/Services/LlmLogService.ts +46 -2
  61. package/Server/Services/OpenTelemetryIngestService.ts +230 -26
  62. package/Server/Services/UserService.ts +184 -0
  63. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +6 -0
  64. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +4 -0
  65. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +8 -5
  66. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +90 -16
  67. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +2 -0
  68. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +2 -0
  69. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +223 -22
  70. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +25 -24
  71. package/Server/Utils/AI/SRE/ConfidenceSignal.ts +182 -71
  72. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +252 -43
  73. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +25 -24
  74. package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +47 -13
  75. package/Server/Utils/AI/SRE/InvestigationGrader.ts +9 -5
  76. package/Server/Utils/AI/SRE/InvestigationQueue.ts +141 -24
  77. package/Server/Utils/AI/SRE/InvestigationSubjectLock.ts +66 -0
  78. package/Server/Utils/AI/SRE/PostedRootCause.ts +94 -3
  79. package/Server/Utils/AI/SRE/README.md +1 -1
  80. package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +132 -10
  81. package/Server/Utils/AI/Toolbox/CodeTools.ts +45 -4
  82. package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +24 -0
  83. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +13 -0
  84. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +157 -4
  85. package/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.ts +130 -0
  86. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +29 -0
  87. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +56 -0
  88. package/Server/Utils/Monitor/MonitorMetricUtil.ts +46 -0
  89. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
  90. package/Server/Utils/PasswordHash.ts +330 -0
  91. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +251 -0
  92. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +747 -0
  93. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +480 -0
  94. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1184 -0
  95. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +500 -0
  96. package/Tests/App/Dashboard/OverviewCustomFields.test.tsx +333 -0
  97. package/Tests/App/Dashboard/PortMonitorCriteriaFilter.test.ts +93 -0
  98. package/Tests/App/Dashboard/UserCustomFields.test.tsx +392 -0
  99. package/Tests/App/StatusPage/PublicStatusPageAPIErrorHandling.test.ts +117 -0
  100. package/Tests/App/StatusPage/StatusPageModelAPIPolymorphism.test.ts +223 -0
  101. package/Tests/Models/DatabaseModels/PermissionCatalogueCoverage.test.ts +243 -0
  102. package/Tests/Server/API/AIAgentDataFixFromIncidentContext.test.ts +266 -0
  103. package/Tests/Server/API/AIAgentDataRepositoryToken.test.ts +381 -0
  104. package/Tests/Server/API/AIInvestigationAPI.test.ts +594 -0
  105. package/Tests/Server/API/AIInvestigationCreateFixTask.test.ts +80 -0
  106. package/Tests/Server/API/DashboardMasterPasswordAPI.test.ts +172 -1
  107. package/Tests/Server/API/DashboardPublicAttributeValuesAPI.test.ts +943 -0
  108. package/Tests/Server/API/DashboardPublicMetricsAggregateAPI.test.ts +1296 -0
  109. package/Tests/Server/API/DashboardPublicTemplatePayloads.test.ts +598 -0
  110. package/Tests/Server/API/GitHubAppInstallationBindingAPI.test.ts +539 -0
  111. package/Tests/Server/API/Helpers.ts +6 -1
  112. package/Tests/Server/API/StatusPageMasterPasswordAPI.test.ts +335 -0
  113. package/Tests/Server/API/UserProjectsAPI.test.ts +852 -0
  114. package/Tests/Server/Infrastructure/GlobalCache.test.ts +128 -0
  115. package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +215 -0
  116. package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +59 -5
  117. package/Tests/Server/Services/AIRunHumanVerdict.test.ts +127 -58
  118. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +396 -20
  119. package/Tests/Server/Services/AddMasterPasswordSaltMigration.test.ts +283 -0
  120. package/Tests/Server/Services/AddPerUserPasswordSaltMigration.test.ts +178 -0
  121. package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +582 -0
  122. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +30 -1
  123. package/Tests/Server/Services/CodeRepositoryInstallationBinding.test.ts +305 -0
  124. package/Tests/Server/Services/CodeRepositoryResolutionBinding.test.ts +147 -0
  125. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +880 -0
  126. package/Tests/Server/Services/DatabaseServiceUpdateColumnsWithoutHooks.test.ts +54 -0
  127. package/Tests/Server/Services/FeedAIRunAssociation.test.ts +125 -0
  128. package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +418 -57
  129. package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +173 -14
  130. package/Tests/Server/Services/MasterPasswordScrypt.test.ts +567 -0
  131. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +568 -0
  132. package/Tests/Server/Services/RestoreDroppedUniqueIndexesMigration.test.ts +386 -0
  133. package/Tests/Server/Services/RestoreServiceLowerNameIndexMigration.test.ts +240 -0
  134. package/Tests/Server/Services/SeparateIncidentAlertAiSettingsMigration.test.ts +194 -0
  135. package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +885 -0
  136. package/Tests/Server/Services/WidenHashedStringColumnsForScryptMigration.test.ts +220 -0
  137. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +37 -4
  138. package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +330 -29
  139. package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +25 -0
  140. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +293 -5
  141. package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +59 -1
  142. package/Tests/Server/Utils/AI/CodeTools.test.ts +47 -1
  143. package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +10 -0
  144. package/Tests/Server/Utils/AI/FixFromIncidentAutoTrigger.test.ts +342 -19
  145. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +214 -30
  146. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +2 -0
  147. package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +65 -17
  148. package/Tests/Server/Utils/AI/InvestigationQueueRemediationExecution.test.ts +3 -0
  149. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +313 -20
  150. package/Tests/Server/Utils/AI/PostedRootCause.test.ts +254 -0
  151. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +4 -0
  152. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +2 -0
  153. package/Tests/Server/Utils/AI/SubjectCodeFixRunDedupe.test.ts +44 -0
  154. package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +30 -0
  155. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +120 -0
  156. package/Tests/Server/Utils/CodeRepository/GitHubInstallationBinding.test.ts +292 -0
  157. package/Tests/Server/Utils/GitHubInstallationOwnershipVerification.test.ts +340 -0
  158. package/Tests/Server/Utils/GitHubWebhookAndTreeCacheIsolation.test.ts +250 -0
  159. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +212 -0
  160. package/Tests/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.test.ts +401 -0
  161. package/Tests/Server/Utils/Monitor/MonitorMetricUtilPortTimings.test.ts +243 -0
  162. package/Tests/Server/Utils/PasswordHash.test.ts +585 -0
  163. package/Tests/Types/Dashboard/DashboardTemplates.test.ts +111 -0
  164. package/Tests/Types/Database/ColumnLength.test.ts +7 -1
  165. package/Tests/Types/HashedStringPerUserSalt.test.ts +476 -0
  166. package/Tests/Types/Monitor/CephMetricCatalog.test.ts +104 -0
  167. package/Tests/Types/Monitor/CriteriaFilter.test.ts +4 -0
  168. package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +293 -0
  169. package/Tests/Types/Monitor/DockerMetricCatalog.test.ts +109 -0
  170. package/Tests/Types/Monitor/DockerSwarmMetricCatalog.test.ts +118 -0
  171. package/Tests/Types/Monitor/HostAlertTemplates.test.ts +249 -0
  172. package/Tests/Types/Monitor/HostMetricCatalog.test.ts +104 -0
  173. package/Tests/Types/Monitor/IotAlertTemplates.test.ts +320 -0
  174. package/Tests/Types/Monitor/IotMetricCatalog.test.ts +104 -0
  175. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +118 -0
  176. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +42 -0
  177. package/Tests/Types/Monitor/MonitorStep.test.ts +38 -0
  178. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +75 -0
  179. package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +271 -0
  180. package/Tests/Types/Monitor/PodmanMetricCatalog.test.ts +109 -0
  181. package/Tests/Types/Monitor/ProxmoxMetricCatalog.test.ts +107 -0
  182. package/Tests/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.test.ts +151 -0
  183. package/Tests/Types/Permission.test.ts +137 -0
  184. package/Tests/Types/Rum/SessionReplayMaskingMode.test.ts +101 -0
  185. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +5 -5
  186. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +3 -5
  187. package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +696 -0
  188. package/Tests/UI/Components/ErrorBoundary.test.tsx +158 -0
  189. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +74 -0
  190. package/Tests/UI/Components/MoreMenu.test.tsx +756 -0
  191. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +62 -0
  192. package/Tests/UI/Monitor/PortMonitorView.test.tsx +237 -0
  193. package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +91 -0
  194. package/Tests/UI/Utils/DownloadFile.test.ts +103 -0
  195. package/Tests/UI/Utils/ErrorSupportBundle.test.ts +582 -0
  196. package/Tests/UI/Utils/Project.test.ts +31 -0
  197. package/Tests/UI/Utils/StatusPageModelAPIInjection.test.ts +245 -0
  198. package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +820 -0
  199. package/Tests/UI/Utils/UserProjectsModelAPI.test.ts +714 -0
  200. package/Tests/Utils/Dashboard/DashboardViewConfig.test.ts +329 -0
  201. package/Tests/Utils/Dashboard/GridLayout.test.ts +951 -0
  202. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +117 -0
  203. package/Tests/Utils/RecordingRuleExpression.test.ts +327 -0
  204. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +186 -0
  205. package/Tests/Utils/StatusPage/GroupTree.test.ts +456 -0
  206. package/Tests/Utils/StatusPage/OverviewGroupHierarchyVisibility.test.ts +588 -0
  207. package/Tests/Utils/TeamMembersByProject.test.ts +655 -0
  208. package/Tests/Utils/Telemetry/SavedViewTimeRange.test.ts +244 -0
  209. package/Tests/Utils/Telemetry/TelemetryQueryTimeRange.test.ts +825 -0
  210. package/Types/AI/AIRunCodeFixRecommendation.ts +17 -0
  211. package/Types/AI/CodeFixTaskContext.ts +63 -3
  212. package/Types/AI/CodeFixTaskType.ts +3 -3
  213. package/Types/Database/ColumnLength.ts +9 -1
  214. package/Types/Database/TableColumn.ts +11 -0
  215. package/Types/Database/UnsynchronizedIndex.ts +48 -0
  216. package/Types/HashedString.ts +140 -4
  217. package/Types/Monitor/CriteriaFilter.ts +4 -0
  218. package/Types/Monitor/DomainMonitor/DomainLookupMethod.ts +23 -0
  219. package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +7 -0
  220. package/Types/Monitor/MonitorCriteriaInstance.ts +24 -7
  221. package/Types/Monitor/MonitorMetricType.ts +8 -0
  222. package/Types/Monitor/MonitorStep.ts +10 -1
  223. package/Types/Monitor/MonitorStepDomainMonitor.ts +21 -0
  224. package/Types/Monitor/PortMonitor/PortMonitorTimings.ts +10 -0
  225. package/Types/Permission.ts +23 -175
  226. package/Types/Probe/ProbeMonitorResponse.ts +6 -0
  227. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +2 -3
  228. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +85 -11
  229. package/UI/Components/ErrorBoundary.tsx +138 -11
  230. package/UI/Components/Feed/FeedItem.tsx +9 -2
  231. package/UI/Components/ModelDetail/CardModelDetail.tsx +0 -12
  232. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  233. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +12 -2
  234. package/UI/Components/MoreMenu/MoreMenu.tsx +285 -97
  235. package/UI/Components/MoreMenu/MoreMenuItem.tsx +8 -5
  236. package/UI/Components/Navbar/NavBar.tsx +12 -2
  237. package/UI/Components/Navbar/NavBarMenuModal.tsx +19 -7
  238. package/UI/Utils/DownloadFile.ts +16 -8
  239. package/UI/Utils/ErrorSupportBundle.ts +805 -0
  240. package/UI/Utils/ModelAPI/ModelAPI.ts +19 -8
  241. package/UI/Utils/ModelAPI/UserProjectsModelAPI.ts +257 -0
  242. package/UI/Utils/Project.ts +4 -0
  243. package/UI/Utils/StatusPage.ts +8 -2
  244. package/UI/Utils/UseDashboardGridDnd.ts +917 -0
  245. package/Utils/Dashboard/DashboardViewConfig.ts +80 -36
  246. package/Utils/Dashboard/GridLayout.ts +523 -0
  247. package/Utils/Metrics/RecordingRuleExpression.ts +19 -17
  248. package/Utils/Monitor/MonitorMetricType.ts +44 -2
  249. package/Utils/StatusPage/GroupNestingLayout.ts +69 -0
  250. package/Utils/StatusPage/GroupTree.ts +157 -66
  251. package/Utils/StatusPage/ResourceUptime.ts +37 -2
  252. package/Utils/TeamMembersByProject.ts +237 -0
  253. package/Utils/Telemetry/SavedViewTimeRange.ts +114 -0
  254. package/Utils/Telemetry/TelemetryQueryTimeRange.ts +334 -0
  255. package/build/dist/Models/DatabaseModels/AIRun.js +39 -1
  256. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  257. package/build/dist/Models/DatabaseModels/AlertFeed.js +32 -0
  258. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  259. package/build/dist/Models/DatabaseModels/CephCluster.js +16 -1
  260. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  261. package/build/dist/Models/DatabaseModels/CodeRepository.js +14 -6
  262. package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
  263. package/build/dist/Models/DatabaseModels/Dashboard.js +29 -0
  264. package/build/dist/Models/DatabaseModels/Dashboard.js.map +1 -1
  265. package/build/dist/Models/DatabaseModels/DockerHost.js +16 -1
  266. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  267. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +16 -1
  268. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  269. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +16 -1
  270. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  271. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  272. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  273. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  274. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  275. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  276. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  277. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  278. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  279. package/build/dist/Models/DatabaseModels/IncidentFeed.js +32 -0
  280. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  281. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  282. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  283. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  284. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  285. package/build/dist/Models/DatabaseModels/IoTFleet.js +16 -1
  286. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  287. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +16 -1
  288. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  289. package/build/dist/Models/DatabaseModels/LogSavedView.js +33 -0
  290. package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
  291. package/build/dist/Models/DatabaseModels/NetworkDevice.js +16 -1
  292. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  293. package/build/dist/Models/DatabaseModels/NetworkInterface.js +16 -1
  294. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
  295. package/build/dist/Models/DatabaseModels/Project.js +257 -13
  296. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  297. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +16 -1
  298. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  299. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  300. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  301. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  302. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  303. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  304. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  305. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +4 -4
  306. package/build/dist/Models/DatabaseModels/Service.js +28 -1
  307. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  308. package/build/dist/Models/DatabaseModels/StatusPage.js +29 -0
  309. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  310. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  311. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  312. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +32 -0
  313. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
  314. package/build/dist/Models/DatabaseModels/User.js +32 -0
  315. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  316. package/build/dist/Server/API/AIAgentDataAPI.js +49 -48
  317. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  318. package/build/dist/Server/API/AIInvestigationAPI.js +111 -11
  319. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  320. package/build/dist/Server/API/DashboardAPI.js +312 -15
  321. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  322. package/build/dist/Server/API/GitHubAPI.js +94 -167
  323. package/build/dist/Server/API/GitHubAPI.js.map +1 -1
  324. package/build/dist/Server/API/StatusPageAPI.js +29 -11
  325. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  326. package/build/dist/Server/API/UserAPI.js +187 -2
  327. package/build/dist/Server/API/UserAPI.js.map +1 -1
  328. package/build/dist/Server/EnvironmentConfig.js +21 -3
  329. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  330. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +12 -1
  331. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  332. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +1 -1
  333. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
  334. package/build/dist/Server/Infrastructure/GlobalCache.js +29 -0
  335. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  336. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js +14 -0
  337. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js.map +1 -0
  338. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js +59 -0
  339. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js.map +1 -0
  340. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js +22 -0
  341. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js.map +1 -0
  342. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +93 -0
  343. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js.map +1 -0
  344. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js +36 -0
  345. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js.map +1 -0
  346. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js +18 -0
  347. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js.map +1 -0
  348. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js +101 -0
  349. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js.map +1 -0
  350. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js +66 -0
  351. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js.map +1 -0
  352. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js +19 -0
  353. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js.map +1 -0
  354. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js +19 -0
  355. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js.map +1 -0
  356. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
  357. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  358. package/build/dist/Server/Services/AIRunService.js +58 -12
  359. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  360. package/build/dist/Server/Services/AIService.js +74 -21
  361. package/build/dist/Server/Services/AIService.js.map +1 -1
  362. package/build/dist/Server/Services/AlertFeedService.js +3 -0
  363. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  364. package/build/dist/Server/Services/AnalyticsDatabaseService.js +86 -2
  365. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  366. package/build/dist/Server/Services/CodeRepositoryService.js +90 -2
  367. package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -1
  368. package/build/dist/Server/Services/DatabaseService.js +180 -3
  369. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  370. package/build/dist/Server/Services/IncidentFeedService.js +3 -0
  371. package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
  372. package/build/dist/Server/Services/LlmLogService.js +22 -1
  373. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  374. package/build/dist/Server/Services/OpenTelemetryIngestService.js +155 -25
  375. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  376. package/build/dist/Server/Services/UserService.js +165 -0
  377. package/build/dist/Server/Services/UserService.js.map +1 -1
  378. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  379. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  380. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +4 -0
  381. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
  382. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +8 -5
  383. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  384. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +63 -24
  385. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  386. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +2 -0
  387. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  388. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +2 -0
  389. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  390. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +156 -28
  391. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  392. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +21 -19
  393. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  394. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +128 -49
  395. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -1
  396. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +170 -31
  397. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -1
  398. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +21 -19
  399. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  400. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +33 -9
  401. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -1
  402. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +9 -5
  403. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -1
  404. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +121 -41
  405. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  406. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js +46 -0
  407. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js.map +1 -0
  408. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js +61 -14
  409. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js.map +1 -1
  410. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +79 -1
  411. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
  412. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +31 -1
  413. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -1
  414. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +21 -0
  415. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
  416. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +13 -0
  417. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  418. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +126 -4
  419. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  420. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js +136 -0
  421. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js.map +1 -0
  422. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +20 -3
  423. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  424. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +43 -0
  425. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
  426. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  427. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  428. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
  429. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  430. package/build/dist/Server/Utils/PasswordHash.js +258 -0
  431. package/build/dist/Server/Utils/PasswordHash.js.map +1 -0
  432. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js +18 -0
  433. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js.map +1 -0
  434. package/build/dist/Types/AI/CodeFixTaskContext.js +23 -3
  435. package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
  436. package/build/dist/Types/AI/CodeFixTaskType.js +3 -3
  437. package/build/dist/Types/Database/ColumnLength.js +9 -1
  438. package/build/dist/Types/Database/ColumnLength.js.map +1 -1
  439. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  440. package/build/dist/Types/Database/UnsynchronizedIndex.js +46 -0
  441. package/build/dist/Types/Database/UnsynchronizedIndex.js.map +1 -0
  442. package/build/dist/Types/HashedString.js +96 -5
  443. package/build/dist/Types/HashedString.js.map +1 -1
  444. package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
  445. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  446. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js +24 -0
  447. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js.map +1 -0
  448. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +24 -7
  449. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  450. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  451. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  452. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  453. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  454. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +15 -0
  455. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
  456. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js +2 -0
  457. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js.map +1 -0
  458. package/build/dist/Types/Permission.js +23 -155
  459. package/build/dist/Types/Permission.js.map +1 -1
  460. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +2 -5
  461. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  462. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +51 -10
  463. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  464. package/build/dist/UI/Components/ErrorBoundary.js +67 -8
  465. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  466. package/build/dist/UI/Components/Feed/FeedItem.js +2 -2
  467. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  468. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +0 -12
  469. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  470. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  471. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  472. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +12 -2
  473. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  474. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +193 -65
  475. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  476. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +1 -1
  477. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  478. package/build/dist/UI/Components/Navbar/NavBar.js +3 -1
  479. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  480. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +19 -7
  481. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  482. package/build/dist/UI/Utils/DownloadFile.js +15 -8
  483. package/build/dist/UI/Utils/DownloadFile.js.map +1 -1
  484. package/build/dist/UI/Utils/ErrorSupportBundle.js +476 -0
  485. package/build/dist/UI/Utils/ErrorSupportBundle.js.map +1 -0
  486. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -8
  487. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  488. package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js +156 -0
  489. package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js.map +1 -0
  490. package/build/dist/UI/Utils/Project.js +3 -0
  491. package/build/dist/UI/Utils/Project.js.map +1 -1
  492. package/build/dist/UI/Utils/StatusPage.js +4 -4
  493. package/build/dist/UI/Utils/StatusPage.js.map +1 -1
  494. package/build/dist/UI/Utils/UseDashboardGridDnd.js +551 -0
  495. package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -0
  496. package/build/dist/Utils/Dashboard/DashboardViewConfig.js +42 -26
  497. package/build/dist/Utils/Dashboard/DashboardViewConfig.js.map +1 -1
  498. package/build/dist/Utils/Dashboard/GridLayout.js +338 -0
  499. package/build/dist/Utils/Dashboard/GridLayout.js.map +1 -0
  500. package/build/dist/Utils/Metrics/RecordingRuleExpression.js +19 -17
  501. package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -1
  502. package/build/dist/Utils/Monitor/MonitorMetricType.js +38 -6
  503. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  504. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +46 -0
  505. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -1
  506. package/build/dist/Utils/StatusPage/GroupTree.js +79 -34
  507. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -1
  508. package/build/dist/Utils/StatusPage/ResourceUptime.js +22 -1
  509. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  510. package/build/dist/Utils/TeamMembersByProject.js +145 -0
  511. package/build/dist/Utils/TeamMembersByProject.js.map +1 -0
  512. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js +79 -0
  513. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js.map +1 -0
  514. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js +236 -0
  515. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js.map +1 -0
  516. package/package.json +1 -1
@@ -0,0 +1,249 @@
1
+ import {
2
+ HostAlertTemplate,
3
+ HostAlertTemplateArgs,
4
+ HostAlertTemplateCategory,
5
+ getAllHostAlertTemplates,
6
+ getHostAlertTemplateById,
7
+ getHostAlertTemplatesByCategory,
8
+ } from "../../../Types/Monitor/HostAlertTemplates";
9
+ import MonitorStep from "../../../Types/Monitor/MonitorStep";
10
+ import MonitorStepHostMonitor from "../../../Types/Monitor/MonitorStepHostMonitor";
11
+ import MetricsAggregationType from "../../../Types/Metrics/MetricsAggregationType";
12
+ import { FilterType } from "../../../Types/Monitor/CriteriaFilter";
13
+ import ObjectID from "../../../Types/ObjectID";
14
+
15
+ /*
16
+ * Host resource templates. The regression-prone details these tests pin:
17
+ *
18
+ * 1. The OTel metric name each template reads (system.cpu.utilization,
19
+ * system.memory.utilization, ...). A rename in the host receiver would
20
+ * make the template match nothing while staying "registered".
21
+ *
22
+ * 2. Ratio metrics are on a [0, 1] scale, so a "90%" threshold is the
23
+ * literal 0.9 — NOT 90. A slip to 90 makes the utilization templates
24
+ * unreachable (utilization never exceeds 1). Load average and process
25
+ * count are raw counts, so their thresholds (4, 2000) are literal.
26
+ *
27
+ * 3. Aggregation: filesystem usage and process count use `Max` so a single
28
+ * full mount / one runaway host trips the alert instead of being averaged
29
+ * away; the rest use `Avg` for a representative sustained reading.
30
+ *
31
+ * 4. The unhealthy/healthy criteria partition the range at the threshold
32
+ * with `>` / `<=` — no gap, no overlap.
33
+ */
34
+
35
+ interface HostTemplateCase {
36
+ id: string;
37
+ category: HostAlertTemplateCategory;
38
+ severity: "Critical" | "Warning";
39
+ metricName: string;
40
+ metricAlias: string;
41
+ aggregation: MetricsAggregationType;
42
+ threshold: number;
43
+ }
44
+
45
+ const HOST_TEMPLATES: Array<HostTemplateCase> = [
46
+ {
47
+ id: "host-high-cpu",
48
+ category: "Resource",
49
+ severity: "Warning",
50
+ metricName: "system.cpu.utilization",
51
+ metricAlias: "host_cpu",
52
+ aggregation: MetricsAggregationType.Avg,
53
+ threshold: 0.8,
54
+ },
55
+ {
56
+ id: "host-high-memory",
57
+ category: "Resource",
58
+ severity: "Warning",
59
+ metricName: "system.memory.utilization",
60
+ metricAlias: "host_memory",
61
+ aggregation: MetricsAggregationType.Avg,
62
+ threshold: 0.85,
63
+ },
64
+ {
65
+ id: "host-high-filesystem",
66
+ category: "Resource",
67
+ severity: "Critical",
68
+ metricName: "system.filesystem.utilization",
69
+ metricAlias: "host_filesystem",
70
+ // Max so a single full filesystem is not diluted by averaging mounts.
71
+ aggregation: MetricsAggregationType.Max,
72
+ threshold: 0.9,
73
+ },
74
+ {
75
+ id: "host-high-load-average",
76
+ category: "Resource",
77
+ severity: "Warning",
78
+ metricName: "system.cpu.load_average.1m",
79
+ metricAlias: "host_load_1m",
80
+ aggregation: MetricsAggregationType.Avg,
81
+ // Load average is a raw count, not a ratio — threshold is literal 4.
82
+ threshold: 4,
83
+ },
84
+ {
85
+ id: "host-high-processes",
86
+ category: "Host",
87
+ severity: "Warning",
88
+ metricName: "system.processes.count",
89
+ metricAlias: "host_processes",
90
+ aggregation: MetricsAggregationType.Max,
91
+ threshold: 2000,
92
+ },
93
+ ];
94
+
95
+ function buildArgs(): HostAlertTemplateArgs {
96
+ return {
97
+ hostIdentifier: "host-01",
98
+ onlineMonitorStatusId: ObjectID.generate(),
99
+ offlineMonitorStatusId: ObjectID.generate(),
100
+ defaultIncidentSeverityId: ObjectID.generate(),
101
+ defaultAlertSeverityId: ObjectID.generate(),
102
+ monitorName: "Test Host Monitor",
103
+ };
104
+ }
105
+
106
+ function getHostMonitor(step: MonitorStep): MonitorStepHostMonitor {
107
+ const hostMonitor: MonitorStepHostMonitor | undefined =
108
+ step.data?.hostMonitor;
109
+ if (!hostMonitor) {
110
+ throw new Error("hostMonitor missing from monitor step");
111
+ }
112
+ return hostMonitor;
113
+ }
114
+
115
+ describe("HostAlertTemplates", () => {
116
+ test("every documented template id is registered and the suite is exhaustive", () => {
117
+ const ids: Array<string> = getAllHostAlertTemplates().map(
118
+ (t: HostAlertTemplate) => {
119
+ return t.id;
120
+ },
121
+ );
122
+ for (const tc of HOST_TEMPLATES) {
123
+ expect(ids).toContain(tc.id);
124
+ }
125
+ expect(ids.sort()).toEqual(
126
+ HOST_TEMPLATES.map((t: HostTemplateCase) => {
127
+ return t.id;
128
+ }).sort(),
129
+ );
130
+ });
131
+
132
+ test("every template id is unique", () => {
133
+ const ids: Array<string> = getAllHostAlertTemplates().map(
134
+ (t: HostAlertTemplate) => {
135
+ return t.id;
136
+ },
137
+ );
138
+ expect(new Set(ids).size).toBe(ids.length);
139
+ });
140
+
141
+ test("getHostAlertTemplateById returns undefined for an unknown id", () => {
142
+ expect(getHostAlertTemplateById("host-nothing")).toBeUndefined();
143
+ });
144
+
145
+ test("getHostAlertTemplatesByCategory returns only that category and covers the catalog", () => {
146
+ const all: Array<HostAlertTemplate> = getAllHostAlertTemplates();
147
+ const categories: Array<HostAlertTemplateCategory> = ["Resource", "Host"];
148
+
149
+ let total: number = 0;
150
+ for (const category of categories) {
151
+ const inCategory: Array<HostAlertTemplate> =
152
+ getHostAlertTemplatesByCategory(category);
153
+ for (const template of inCategory) {
154
+ expect(template.category).toBe(category);
155
+ }
156
+ total += inCategory.length;
157
+ }
158
+ expect(total).toBe(all.length);
159
+ });
160
+
161
+ test.each(HOST_TEMPLATES)(
162
+ "$id is a $severity $category template with populated copy",
163
+ (tc: HostTemplateCase) => {
164
+ const template: HostAlertTemplate | undefined = getHostAlertTemplateById(
165
+ tc.id,
166
+ );
167
+ expect(template).toBeDefined();
168
+ expect(template!.category).toBe(tc.category);
169
+ expect(template!.severity).toBe(tc.severity);
170
+ expect(template!.name.length).toBeGreaterThan(0);
171
+ expect(template!.description.length).toBeGreaterThan(0);
172
+ },
173
+ );
174
+
175
+ test.each(HOST_TEMPLATES)(
176
+ "$id queries $metricName with the intended aggregation",
177
+ (tc: HostTemplateCase) => {
178
+ const template: HostAlertTemplate = getHostAlertTemplateById(tc.id)!;
179
+ const step: MonitorStep = template.getMonitorStep(buildArgs());
180
+ const monitor: MonitorStepHostMonitor = getHostMonitor(step);
181
+
182
+ expect(monitor.hostIdentifier).toBe("host-01");
183
+
184
+ const queryConfigs: Array<any> = monitor.metricViewConfig
185
+ .queryConfigs as Array<any>;
186
+ expect(queryConfigs).toHaveLength(1);
187
+ expect(monitor.metricViewConfig.formulaConfigs).toHaveLength(0);
188
+
189
+ const filterData: any = queryConfigs[0].metricQueryData.filterData;
190
+ expect(filterData.metricName).toBe(tc.metricName);
191
+ expect(filterData.aggegationType).toBe(tc.aggregation);
192
+ },
193
+ );
194
+
195
+ test.each(HOST_TEMPLATES)(
196
+ "$id unhealthy/healthy criteria partition the range at $threshold with > / <=",
197
+ (tc: HostTemplateCase) => {
198
+ const template: HostAlertTemplate = getHostAlertTemplateById(tc.id)!;
199
+ const step: MonitorStep = template.getMonitorStep(buildArgs());
200
+
201
+ const instances: Array<any> = step.data?.monitorCriteria.data
202
+ ?.monitorCriteriaInstanceArray as Array<any>;
203
+ expect(instances).toHaveLength(2);
204
+ const [offline, online] = instances;
205
+
206
+ const offlineFilter: any = offline.data.filters[0];
207
+ const onlineFilter: any = online.data.filters[0];
208
+
209
+ expect(offlineFilter.metricMonitorOptions.metricAlias).toBe(
210
+ tc.metricAlias,
211
+ );
212
+ expect(onlineFilter.metricMonitorOptions.metricAlias).toBe(
213
+ tc.metricAlias,
214
+ );
215
+ expect(offlineFilter.value).toBe(tc.threshold);
216
+ expect(onlineFilter.value).toBe(tc.threshold);
217
+
218
+ // Host ceilings are all "> threshold" unhealthy / "<= threshold" healthy.
219
+ expect(offlineFilter.filterType).toBe(FilterType.GreaterThan);
220
+ expect(onlineFilter.filterType).toBe(FilterType.LessThanOrEqualTo);
221
+
222
+ expect(offline.data.createIncidents).toBe(true);
223
+ expect(offline.data.createAlerts).toBe(true);
224
+ expect(online.data.createIncidents).toBe(false);
225
+ expect(online.data.createAlerts).toBe(false);
226
+ },
227
+ );
228
+
229
+ test("ratio-metric thresholds stay on the 0-1 scale, not 0-100", () => {
230
+ /*
231
+ * A "90%" threshold written as 90 would make a utilization ([0,1])
232
+ * template unreachable. Lock the utilization templates below 1.
233
+ */
234
+ const ratioIds: Array<string> = [
235
+ "host-high-cpu",
236
+ "host-high-memory",
237
+ "host-high-filesystem",
238
+ ];
239
+ for (const id of ratioIds) {
240
+ const tc: HostTemplateCase = HOST_TEMPLATES.find(
241
+ (t: HostTemplateCase) => {
242
+ return t.id === id;
243
+ },
244
+ )!;
245
+ expect(tc.threshold).toBeGreaterThan(0);
246
+ expect(tc.threshold).toBeLessThanOrEqual(1);
247
+ }
248
+ });
249
+ });
@@ -0,0 +1,104 @@
1
+ import {
2
+ HostMetricCategory,
3
+ HostMetricDefinition,
4
+ getAllHostMetricCategories,
5
+ getAllHostMetrics,
6
+ getHostMetricById,
7
+ getHostMetricByMetricName,
8
+ getHostMetricsByCategory,
9
+ } from "../../../Types/Monitor/HostMetricCatalog";
10
+ import AggregationType from "../../../Types/BaseDatabase/AggregationType";
11
+ import { describe, expect, test } from "@jest/globals";
12
+
13
+ describe("HostMetricCatalog", () => {
14
+ const allMetrics: Array<HostMetricDefinition> = getAllHostMetrics();
15
+ const allCategories: Array<HostMetricCategory> = getAllHostMetricCategories();
16
+ const validAggregations: Array<string> = Object.values(AggregationType);
17
+
18
+ test("returns a non-empty catalog", () => {
19
+ expect(Array.isArray(allMetrics)).toBe(true);
20
+ expect(allMetrics.length).toBeGreaterThan(0);
21
+ });
22
+
23
+ test("every metric definition has all required non-empty fields", () => {
24
+ for (const metric of allMetrics) {
25
+ expect(typeof metric.id).toBe("string");
26
+ expect(metric.id.length).toBeGreaterThan(0);
27
+ expect(metric.friendlyName.length).toBeGreaterThan(0);
28
+ expect(metric.description.length).toBeGreaterThan(0);
29
+ expect(metric.metricName.length).toBeGreaterThan(0);
30
+ expect(metric.category.length).toBeGreaterThan(0);
31
+ }
32
+ });
33
+
34
+ test("every metric uses a valid aggregation type", () => {
35
+ for (const metric of allMetrics) {
36
+ expect(validAggregations).toContain(metric.defaultAggregation);
37
+ }
38
+ });
39
+
40
+ test("metric ids are unique", () => {
41
+ const ids: Array<string> = allMetrics.map((m: HostMetricDefinition) => {
42
+ return m.id;
43
+ });
44
+ expect(new Set(ids).size).toBe(ids.length);
45
+ });
46
+
47
+ test("metric names are unique", () => {
48
+ const names: Array<string> = allMetrics.map((m: HostMetricDefinition) => {
49
+ return m.metricName;
50
+ });
51
+ expect(new Set(names).size).toBe(names.length);
52
+ });
53
+
54
+ test("every metric category is a declared category", () => {
55
+ for (const metric of allMetrics) {
56
+ expect(allCategories).toContain(metric.category);
57
+ }
58
+ });
59
+
60
+ test("declared categories are unique and non-empty", () => {
61
+ expect(allCategories.length).toBeGreaterThan(0);
62
+ expect(new Set(allCategories).size).toBe(allCategories.length);
63
+ });
64
+
65
+ test("every declared category has at least one metric", () => {
66
+ for (const category of allCategories) {
67
+ expect(getHostMetricsByCategory(category).length).toBeGreaterThan(0);
68
+ }
69
+ });
70
+
71
+ test("getHostMetricsByCategory returns only metrics of that category", () => {
72
+ for (const category of allCategories) {
73
+ for (const metric of getHostMetricsByCategory(category)) {
74
+ expect(metric.category).toBe(category);
75
+ }
76
+ }
77
+ });
78
+
79
+ test("getHostMetricById round-trips every metric", () => {
80
+ for (const metric of allMetrics) {
81
+ expect(getHostMetricById(metric.id)).toEqual(metric);
82
+ }
83
+ });
84
+
85
+ test("getHostMetricById returns undefined for an unknown id", () => {
86
+ expect(getHostMetricById("does-not-exist")).toBeUndefined();
87
+ expect(getHostMetricById("")).toBeUndefined();
88
+ });
89
+
90
+ test("getHostMetricByMetricName round-trips every metric", () => {
91
+ for (const metric of allMetrics) {
92
+ expect(getHostMetricByMetricName(metric.metricName)).toEqual(metric);
93
+ }
94
+ });
95
+
96
+ test("getHostMetricByMetricName returns undefined for an unknown name", () => {
97
+ expect(getHostMetricByMetricName("nope.nope")).toBeUndefined();
98
+ });
99
+
100
+ test("known host metrics are present", () => {
101
+ expect(getHostMetricByMetricName("system.cpu.utilization")).toBeDefined();
102
+ expect(getHostMetricByMetricName("system.memory.usage")).toBeDefined();
103
+ });
104
+ });
@@ -0,0 +1,320 @@
1
+ import {
2
+ IoTAlertTemplate,
3
+ IoTAlertTemplateArgs,
4
+ IoTAlertTemplateCategory,
5
+ getAllIoTAlertTemplates,
6
+ getIoTAlertTemplateById,
7
+ getIoTAlertTemplatesByCategory,
8
+ } from "../../../Types/Monitor/IotAlertTemplates";
9
+ import MonitorStep from "../../../Types/Monitor/MonitorStep";
10
+ import MonitorStepIoTMonitor from "../../../Types/Monitor/MonitorStepIoTMonitor";
11
+ import MetricsAggregationType from "../../../Types/Metrics/MetricsAggregationType";
12
+ import {
13
+ FilterType,
14
+ NoDataPolicy,
15
+ } from "../../../Types/Monitor/CriteriaFilter";
16
+ import ObjectID from "../../../Types/ObjectID";
17
+
18
+ /*
19
+ * The IoT templates carry two decisions the container templates don't, and
20
+ * both are the point of this suite:
21
+ *
22
+ * 1. INVERTED thresholds. "Bad" for a device is a value that is too LOW —
23
+ * no heartbeat (iot_device_up < 1), a draining battery (< 20%), a fading
24
+ * radio (< -100 dBm). So the unhealthy criterion is `<` and the healthy
25
+ * one is `>=`, the opposite direction from a CPU/memory ceiling. A
26
+ * copy-paste of a `>`/`<=` pair from the ceiling templates would make the
27
+ * monitor alert exactly when the device is fine. Temperature and CPU are
28
+ * genuine ceilings and keep the `>`/`<=` direction — the mix is what makes
29
+ * pinning each direction per template worthwhile.
30
+ *
31
+ * 2. Per-device grouping. Every template groups by the `device.id` datapoint
32
+ * label (NOT `resource.`-prefixed — it is a datapoint attribute, not a
33
+ * resource attribute) so one incident fires per device rather than one
34
+ * collapsed series for the whole fleet.
35
+ *
36
+ * 3. The Device Offline template — and ONLY it — opts into TreatAsZero so a
37
+ * registered device that goes completely silent (an empty series) folds
38
+ * to 0 and trips `Min(iot_device_up) < 1`. Enabling that on a battery or
39
+ * temperature threshold would false-alarm for any silent device, so the
40
+ * other templates must NOT carry it.
41
+ */
42
+
43
+ interface IoTTemplateCase {
44
+ id: string;
45
+ category: IoTAlertTemplateCategory;
46
+ severity: "Critical" | "Warning";
47
+ metricName: string;
48
+ metricAlias: string;
49
+ aggregation: MetricsAggregationType;
50
+ offlineFilterType: FilterType;
51
+ onlineFilterType: FilterType;
52
+ threshold: number;
53
+ treatNoDataAsZero: boolean;
54
+ }
55
+
56
+ const IOT_TEMPLATES: Array<IoTTemplateCase> = [
57
+ {
58
+ id: "iot-device-offline",
59
+ category: "Availability",
60
+ severity: "Critical",
61
+ metricName: "iot_device_up",
62
+ metricAlias: "device_up",
63
+ // Min: a single down push in the window must win over healthy pushes.
64
+ aggregation: MetricsAggregationType.Min,
65
+ offlineFilterType: FilterType.LessThan,
66
+ onlineFilterType: FilterType.GreaterThanOrEqualTo,
67
+ threshold: 1,
68
+ treatNoDataAsZero: true,
69
+ },
70
+ {
71
+ id: "iot-low-battery",
72
+ category: "Power",
73
+ severity: "Warning",
74
+ metricName: "iot_battery_percent",
75
+ metricAlias: "battery_percent",
76
+ aggregation: MetricsAggregationType.Avg,
77
+ offlineFilterType: FilterType.LessThan,
78
+ onlineFilterType: FilterType.GreaterThanOrEqualTo,
79
+ threshold: 20,
80
+ treatNoDataAsZero: false,
81
+ },
82
+ {
83
+ id: "iot-weak-signal",
84
+ category: "Connectivity",
85
+ severity: "Warning",
86
+ metricName: "iot_signal_strength_dbm",
87
+ metricAlias: "signal_strength",
88
+ aggregation: MetricsAggregationType.Avg,
89
+ offlineFilterType: FilterType.LessThan,
90
+ onlineFilterType: FilterType.GreaterThanOrEqualTo,
91
+ // dBm is negative; -100 is a real threshold, not a placeholder.
92
+ threshold: -100,
93
+ treatNoDataAsZero: false,
94
+ },
95
+ {
96
+ id: "iot-high-temperature",
97
+ category: "Environment",
98
+ severity: "Critical",
99
+ metricName: "iot_temperature_celsius",
100
+ metricAlias: "temperature_celsius",
101
+ // Max: a single hot reading must win over cooler ones in the minute.
102
+ aggregation: MetricsAggregationType.Max,
103
+ offlineFilterType: FilterType.GreaterThan,
104
+ onlineFilterType: FilterType.LessThanOrEqualTo,
105
+ threshold: 70,
106
+ treatNoDataAsZero: false,
107
+ },
108
+ {
109
+ id: "iot-high-cpu",
110
+ category: "System",
111
+ severity: "Warning",
112
+ metricName: "iot_cpu_usage_ratio",
113
+ metricAlias: "cpu_usage",
114
+ aggregation: MetricsAggregationType.Avg,
115
+ offlineFilterType: FilterType.GreaterThan,
116
+ onlineFilterType: FilterType.LessThanOrEqualTo,
117
+ // iot_cpu_usage_ratio is a 0-1 ratio, so 0.9 == 90%.
118
+ threshold: 0.9,
119
+ treatNoDataAsZero: false,
120
+ },
121
+ ];
122
+
123
+ function buildArgs(): IoTAlertTemplateArgs {
124
+ return {
125
+ fleetIdentifier: "field-fleet-a",
126
+ onlineMonitorStatusId: ObjectID.generate(),
127
+ offlineMonitorStatusId: ObjectID.generate(),
128
+ defaultIncidentSeverityId: ObjectID.generate(),
129
+ defaultAlertSeverityId: ObjectID.generate(),
130
+ monitorName: "Test IoT Monitor",
131
+ };
132
+ }
133
+
134
+ function getIoTMonitor(step: MonitorStep): MonitorStepIoTMonitor {
135
+ const iotMonitor: MonitorStepIoTMonitor | undefined = step.data?.iotMonitor;
136
+ if (!iotMonitor) {
137
+ throw new Error("iotMonitor missing from monitor step");
138
+ }
139
+ return iotMonitor;
140
+ }
141
+
142
+ describe("IotAlertTemplates", () => {
143
+ test("every documented template id is registered and the suite is exhaustive", () => {
144
+ const ids: Array<string> = getAllIoTAlertTemplates().map(
145
+ (t: IoTAlertTemplate) => {
146
+ return t.id;
147
+ },
148
+ );
149
+ for (const tc of IOT_TEMPLATES) {
150
+ expect(ids).toContain(tc.id);
151
+ }
152
+ expect(ids.sort()).toEqual(
153
+ IOT_TEMPLATES.map((t: IoTTemplateCase) => {
154
+ return t.id;
155
+ }).sort(),
156
+ );
157
+ });
158
+
159
+ test("every template id is unique", () => {
160
+ const ids: Array<string> = getAllIoTAlertTemplates().map(
161
+ (t: IoTAlertTemplate) => {
162
+ return t.id;
163
+ },
164
+ );
165
+ expect(new Set(ids).size).toBe(ids.length);
166
+ });
167
+
168
+ test("getIoTAlertTemplateById returns undefined for an unknown id", () => {
169
+ expect(getIoTAlertTemplateById("nope")).toBeUndefined();
170
+ });
171
+
172
+ test("getIoTAlertTemplatesByCategory returns only that category and covers the catalog", () => {
173
+ const all: Array<IoTAlertTemplate> = getAllIoTAlertTemplates();
174
+ const categories: Array<IoTAlertTemplateCategory> = [
175
+ "Availability",
176
+ "Power",
177
+ "Connectivity",
178
+ "Environment",
179
+ "System",
180
+ ];
181
+
182
+ let total: number = 0;
183
+ for (const category of categories) {
184
+ const inCategory: Array<IoTAlertTemplate> =
185
+ getIoTAlertTemplatesByCategory(category);
186
+ for (const template of inCategory) {
187
+ expect(template.category).toBe(category);
188
+ }
189
+ total += inCategory.length;
190
+ }
191
+ expect(total).toBe(all.length);
192
+ });
193
+
194
+ test.each(IOT_TEMPLATES)(
195
+ "$id is a $severity $category template with populated copy",
196
+ (tc: IoTTemplateCase) => {
197
+ const template: IoTAlertTemplate | undefined = getIoTAlertTemplateById(
198
+ tc.id,
199
+ );
200
+ expect(template).toBeDefined();
201
+ expect(template!.category).toBe(tc.category);
202
+ expect(template!.severity).toBe(tc.severity);
203
+ expect(template!.name.length).toBeGreaterThan(0);
204
+ expect(template!.description.length).toBeGreaterThan(0);
205
+ },
206
+ );
207
+
208
+ test.each(IOT_TEMPLATES)(
209
+ "$id queries $metricName grouped per device with the intended aggregation",
210
+ (tc: IoTTemplateCase) => {
211
+ const template: IoTAlertTemplate = getIoTAlertTemplateById(tc.id)!;
212
+ const step: MonitorStep = template.getMonitorStep(buildArgs());
213
+ const monitor: MonitorStepIoTMonitor = getIoTMonitor(step);
214
+
215
+ expect(monitor.fleetIdentifier).toBe("field-fleet-a");
216
+
217
+ const queryConfigs: Array<any> = monitor.metricViewConfig
218
+ .queryConfigs as Array<any>;
219
+ expect(queryConfigs).toHaveLength(1);
220
+ expect(monitor.metricViewConfig.formulaConfigs).toHaveLength(0);
221
+
222
+ const queryData: any = queryConfigs[0].metricQueryData;
223
+ expect(queryData.filterData.metricName).toBe(tc.metricName);
224
+ expect(queryData.filterData.aggegationType).toBe(tc.aggregation);
225
+
226
+ /*
227
+ * Decision (2): one incident per device — group by the raw datapoint
228
+ * label, which is NOT resource-prefixed.
229
+ */
230
+ expect(queryData.groupByAttributeKeys).toEqual(["device.id"]);
231
+ expect(queryData.groupByAttributeKeys[0].startsWith("resource.")).toBe(
232
+ false,
233
+ );
234
+ },
235
+ );
236
+
237
+ test.each(IOT_TEMPLATES)(
238
+ "$id unhealthy/healthy criteria partition the range at $threshold",
239
+ (tc: IoTTemplateCase) => {
240
+ const template: IoTAlertTemplate = getIoTAlertTemplateById(tc.id)!;
241
+ const step: MonitorStep = template.getMonitorStep(buildArgs());
242
+
243
+ const instances: Array<any> = step.data?.monitorCriteria.data
244
+ ?.monitorCriteriaInstanceArray as Array<any>;
245
+ expect(instances).toHaveLength(2);
246
+ const [offline, online] = instances;
247
+
248
+ const offlineFilter: any = offline.data.filters[0];
249
+ const onlineFilter: any = online.data.filters[0];
250
+
251
+ expect(offlineFilter.metricMonitorOptions.metricAlias).toBe(
252
+ tc.metricAlias,
253
+ );
254
+ expect(onlineFilter.metricMonitorOptions.metricAlias).toBe(
255
+ tc.metricAlias,
256
+ );
257
+ expect(offlineFilter.value).toBe(tc.threshold);
258
+ expect(onlineFilter.value).toBe(tc.threshold);
259
+
260
+ /*
261
+ * Decision (1): pin the exact comparison direction per template — the
262
+ * low-value alerts invert relative to the ceiling alerts.
263
+ */
264
+ expect(offlineFilter.filterType).toBe(tc.offlineFilterType);
265
+ expect(onlineFilter.filterType).toBe(tc.onlineFilterType);
266
+
267
+ expect(offline.data.createIncidents).toBe(true);
268
+ expect(offline.data.createAlerts).toBe(true);
269
+ expect(online.data.createIncidents).toBe(false);
270
+ expect(online.data.createAlerts).toBe(false);
271
+ },
272
+ );
273
+
274
+ test.each(IOT_TEMPLATES)(
275
+ "$id applies TreatAsZero only when it is the Device Offline template",
276
+ (tc: IoTTemplateCase) => {
277
+ const template: IoTAlertTemplate = getIoTAlertTemplateById(tc.id)!;
278
+ const step: MonitorStep = template.getMonitorStep(buildArgs());
279
+
280
+ const offline: any = (
281
+ step.data?.monitorCriteria.data
282
+ ?.monitorCriteriaInstanceArray as Array<any>
283
+ )[0];
284
+ const online: any = (
285
+ step.data?.monitorCriteria.data
286
+ ?.monitorCriteriaInstanceArray as Array<any>
287
+ )[1];
288
+
289
+ const offlineNoDataPolicy: NoDataPolicy | undefined =
290
+ offline.data.filters[0].metricMonitorOptions.onNoDataPolicy;
291
+
292
+ if (tc.treatNoDataAsZero) {
293
+ // Decision (3): a silent registered device must fold to 0 and alert.
294
+ expect(offlineNoDataPolicy).toBe(NoDataPolicy.TreatAsZero);
295
+ } else {
296
+ // Everything else leaves no-data untouched to avoid false alarms.
297
+ expect(offlineNoDataPolicy).toBeUndefined();
298
+ }
299
+
300
+ // The healthy criterion never overrides the no-data policy.
301
+ expect(
302
+ online.data.filters[0].metricMonitorOptions.onNoDataPolicy,
303
+ ).toBeUndefined();
304
+ },
305
+ );
306
+
307
+ test("exactly one template opts into TreatAsZero", () => {
308
+ /*
309
+ * Guards decision (3) at the catalog level: if a second template ever
310
+ * enables TreatAsZero, this fails and forces a deliberate review.
311
+ */
312
+ const withTreatAsZero: Array<IoTTemplateCase> = IOT_TEMPLATES.filter(
313
+ (tc: IoTTemplateCase) => {
314
+ return tc.treatNoDataAsZero;
315
+ },
316
+ );
317
+ expect(withTreatAsZero).toHaveLength(1);
318
+ expect(withTreatAsZero[0]!.id).toBe("iot-device-offline");
319
+ });
320
+ });