@oneuptime/common 11.4.1 → 11.5.0

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 (321) hide show
  1. package/Models/DatabaseModels/AIRun.ts +50 -0
  2. package/Models/DatabaseModels/AlertSeverity.ts +6 -0
  3. package/Models/DatabaseModels/IncidentSeverity.ts +6 -0
  4. package/Models/DatabaseModels/Index.ts +16 -0
  5. package/Models/DatabaseModels/IoTDeviceCredential.ts +471 -0
  6. package/Models/DatabaseModels/LlmLog.ts +56 -0
  7. package/Models/DatabaseModels/LlmProvider.ts +33 -0
  8. package/Models/DatabaseModels/NetworkDevice.ts +1385 -0
  9. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +717 -0
  10. package/Models/DatabaseModels/NetworkDeviceLabelRule.ts +514 -0
  11. package/Models/DatabaseModels/NetworkDeviceOwnerRule.ts +596 -0
  12. package/Models/DatabaseModels/NetworkDeviceOwnerTeam.ts +487 -0
  13. package/Models/DatabaseModels/NetworkDeviceOwnerUser.ts +486 -0
  14. package/Models/DatabaseModels/NetworkInterface.ts +563 -0
  15. package/Models/DatabaseModels/Project.ts +145 -0
  16. package/Models/DatabaseModels/TelemetryEntityRelationship.ts +54 -0
  17. package/Server/API/AIInvestigationAPI.ts +131 -63
  18. package/Server/API/AlertAPI.ts +5 -0
  19. package/Server/API/IncidentAPI.ts +10 -0
  20. package/Server/API/IncidentEpisodeAPI.ts +5 -0
  21. package/Server/API/LlmProviderAPI.ts +4 -0
  22. package/Server/API/ScheduledMaintenanceAPI.ts +5 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.ts +19 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.ts +25 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.ts +31 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.ts +19 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.ts +105 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.ts +15 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.ts +192 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.ts +37 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.ts +19 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.ts +25 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.ts +31 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.ts +79 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.ts +49 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +24 -0
  37. package/Server/Services/AIRunService.ts +58 -0
  38. package/Server/Services/AIService.ts +101 -0
  39. package/Server/Services/IncidentService.ts +14 -41
  40. package/Server/Services/Index.ts +14 -0
  41. package/Server/Services/IoTDeviceCredentialService.ts +351 -0
  42. package/Server/Services/IoTDeviceService.ts +64 -21
  43. package/Server/Services/LlmLogService.ts +26 -0
  44. package/Server/Services/LlmProviderService.ts +3 -0
  45. package/Server/Services/MonitorService.ts +4 -1
  46. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +10 -0
  47. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +204 -0
  48. package/Server/Services/NetworkDeviceLabelRuleService.ts +14 -0
  49. package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +222 -0
  50. package/Server/Services/NetworkDeviceOwnerRuleService.ts +14 -0
  51. package/Server/Services/NetworkDeviceOwnerTeamService.ts +10 -0
  52. package/Server/Services/NetworkDeviceOwnerUserService.ts +10 -0
  53. package/Server/Services/NetworkDeviceService.ts +50 -0
  54. package/Server/Services/NetworkInterfaceService.ts +10 -0
  55. package/Server/Services/TelemetryEntityRelationshipService.ts +23 -0
  56. package/Server/Services/TelemetryEntityService.ts +72 -2
  57. package/Server/Utils/AI/Sentinel/AlertInvestigationRunner.ts +244 -12
  58. package/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.ts +92 -19
  59. package/Server/Utils/AI/Sentinel/InvestigationQueue.ts +493 -0
  60. package/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.ts +88 -68
  61. package/Server/Utils/AI/Toolbox/Index.ts +2 -1
  62. package/Server/Utils/AI/Toolbox/MetricTools.ts +391 -0
  63. package/Server/Utils/LLM/LLMService.ts +21 -0
  64. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +170 -2
  65. package/Server/Utils/Monitor/IoTDeviceAbsenceSeries.ts +101 -0
  66. package/Server/Utils/Monitor/MonitorAlert.ts +15 -3
  67. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +1 -1
  68. package/Server/Utils/Monitor/MonitorIncident.ts +19 -3
  69. package/Server/Utils/Monitor/MonitorMetricUtil.ts +87 -0
  70. package/Server/Utils/Monitor/MonitorResource.ts +77 -21
  71. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -1
  72. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +201 -0
  73. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +215 -0
  74. package/Server/Utils/Monitor/SnmpInterfaceRateUtil.ts +169 -0
  75. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +173 -0
  76. package/Tests/Server/Services/IncidentInternalNoteAnnouncement.test.ts +97 -0
  77. package/Tests/Server/Services/IoTDeviceService.test.ts +54 -0
  78. package/Tests/Server/Utils/AI/BaselineAnomalyTool.test.ts +253 -0
  79. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +44 -0
  80. package/Tests/Server/Utils/AI/SentinelAlertGating.test.ts +360 -0
  81. package/Tests/Server/Utils/AI/SentinelInvestigationQueue.test.ts +295 -0
  82. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +59 -0
  83. package/Tests/Server/Utils/Monitor/IoTDeviceAbsenceSeries.test.ts +113 -0
  84. package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +198 -0
  85. package/Tests/Types/Monitor/MonitorType.test.ts +1 -1
  86. package/Tests/Utils/Monitor/LatencyMatrixUtil.test.ts +111 -0
  87. package/Types/AI/AIRunStatus.ts +9 -0
  88. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +0 -1
  89. package/Types/Dashboard/DashboardComponents/DashboardLogChartComponent.ts +8 -3
  90. package/Types/LlmLogStatus.ts +1 -0
  91. package/Types/Monitor/CriteriaFilter.ts +5 -0
  92. package/Types/Monitor/IotAlertTemplates.ts +22 -3
  93. package/Types/Monitor/LatencyMatrix.ts +27 -0
  94. package/Types/Monitor/MonitorCriteriaInstance.ts +2 -2
  95. package/Types/Monitor/MonitorMetricType.ts +10 -0
  96. package/Types/Monitor/MonitorStep.ts +36 -11
  97. package/Types/Monitor/MonitorStepNetworkDeviceMonitor.ts +55 -0
  98. package/Types/Monitor/MonitorStepSnmpMonitor.ts +8 -0
  99. package/Types/Monitor/MonitorType.ts +14 -9
  100. package/Types/Monitor/SnmpMonitor/LldpNeighbor.ts +12 -0
  101. package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +116 -0
  102. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +29 -0
  103. package/Types/Monitor/SnmpMonitor/SnmpInterface.ts +31 -0
  104. package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +24 -0
  105. package/Types/Monitor/SnmpMonitor/SnmpTrap.ts +20 -0
  106. package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +173 -0
  107. package/Types/Permission.ts +314 -0
  108. package/Types/Probe/ProbeMonitorResponse.ts +8 -0
  109. package/UI/Components/Icon/Icon.tsx +8 -6
  110. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +2 -2
  111. package/UI/Components/Tabs/Tabs.tsx +10 -1
  112. package/UI/Utils/Navigation.ts +10 -1
  113. package/Utils/Dashboard/Components/DashboardLogChartComponent.ts +16 -21
  114. package/Utils/Monitor/LatencyMatrixUtil.ts +162 -0
  115. package/Utils/Monitor/MonitorMetricType.ts +71 -1
  116. package/Utils/Monitor/NetworkTopologyUtil.ts +159 -0
  117. package/Utils/Telemetry/EntityRelationship.ts +11 -0
  118. package/build/dist/Models/DatabaseModels/AIRun.js +52 -0
  119. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  120. package/build/dist/Models/DatabaseModels/AlertSeverity.js +6 -0
  121. package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
  122. package/build/dist/Models/DatabaseModels/IncidentSeverity.js +6 -0
  123. package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
  124. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  125. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  126. package/build/dist/Models/DatabaseModels/IoTDeviceCredential.js +493 -0
  127. package/build/dist/Models/DatabaseModels/IoTDeviceCredential.js.map +1 -0
  128. package/build/dist/Models/DatabaseModels/LlmLog.js +58 -0
  129. package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -1
  130. package/build/dist/Models/DatabaseModels/LlmProvider.js +33 -0
  131. package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
  132. package/build/dist/Models/DatabaseModels/NetworkDevice.js +1426 -0
  133. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -0
  134. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +738 -0
  135. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -0
  136. package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js +522 -0
  137. package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js.map +1 -0
  138. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js +603 -0
  139. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js.map +1 -0
  140. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js +503 -0
  141. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js.map +1 -0
  142. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js +502 -0
  143. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js.map +1 -0
  144. package/build/dist/Models/DatabaseModels/NetworkInterface.js +589 -0
  145. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -0
  146. package/build/dist/Models/DatabaseModels/Project.js +147 -0
  147. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  148. package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js +57 -0
  149. package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js.map +1 -1
  150. package/build/dist/Server/API/AIInvestigationAPI.js +95 -55
  151. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  152. package/build/dist/Server/API/AlertAPI.js +5 -0
  153. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  154. package/build/dist/Server/API/IncidentAPI.js +10 -0
  155. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  156. package/build/dist/Server/API/IncidentEpisodeAPI.js +5 -0
  157. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  158. package/build/dist/Server/API/LlmProviderAPI.js +5 -7
  159. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  160. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +5 -0
  161. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  162. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.js +12 -0
  163. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.js.map +1 -0
  164. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.js +14 -0
  165. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.js.map +1 -0
  166. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.js +18 -0
  167. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.js.map +1 -0
  168. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.js +12 -0
  169. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.js.map +1 -0
  170. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.js +51 -0
  171. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.js.map +1 -0
  172. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.js +12 -0
  173. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.js.map +1 -0
  174. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.js +101 -0
  175. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.js.map +1 -0
  176. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.js +18 -0
  177. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.js.map +1 -0
  178. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.js +12 -0
  179. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.js.map +1 -0
  180. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.js +14 -0
  181. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.js.map +1 -0
  182. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.js +16 -0
  183. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.js.map +1 -0
  184. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.js +38 -0
  185. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.js.map +1 -0
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.js +22 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.js.map +1 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +24 -0
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  190. package/build/dist/Server/Services/AIRunService.js +33 -0
  191. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  192. package/build/dist/Server/Services/AIService.js +82 -9
  193. package/build/dist/Server/Services/AIService.js.map +1 -1
  194. package/build/dist/Server/Services/IncidentService.js +14 -25
  195. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  196. package/build/dist/Server/Services/Index.js +14 -0
  197. package/build/dist/Server/Services/Index.js.map +1 -1
  198. package/build/dist/Server/Services/IoTDeviceCredentialService.js +321 -0
  199. package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -0
  200. package/build/dist/Server/Services/IoTDeviceService.js +49 -15
  201. package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
  202. package/build/dist/Server/Services/LlmLogService.js +29 -0
  203. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  204. package/build/dist/Server/Services/LlmProviderService.js +3 -0
  205. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  206. package/build/dist/Server/Services/MonitorService.js +2 -1
  207. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  208. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +9 -0
  209. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -0
  210. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +166 -0
  211. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -0
  212. package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js +13 -0
  213. package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js.map +1 -0
  214. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +186 -0
  215. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -0
  216. package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js +13 -0
  217. package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js.map +1 -0
  218. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js +9 -0
  219. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js.map +1 -0
  220. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js +9 -0
  221. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js.map +1 -0
  222. package/build/dist/Server/Services/NetworkDeviceService.js +52 -0
  223. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -0
  224. package/build/dist/Server/Services/NetworkInterfaceService.js +9 -0
  225. package/build/dist/Server/Services/NetworkInterfaceService.js.map +1 -0
  226. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +22 -0
  227. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
  228. package/build/dist/Server/Services/TelemetryEntityService.js +64 -2
  229. package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
  230. package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js +189 -9
  231. package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js.map +1 -1
  232. package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js +84 -17
  233. package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js.map +1 -1
  234. package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js +428 -0
  235. package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js.map +1 -0
  236. package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js +63 -47
  237. package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js.map +1 -1
  238. package/build/dist/Server/Utils/AI/Toolbox/Index.js +2 -1
  239. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  240. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +300 -0
  241. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -1
  242. package/build/dist/Server/Utils/LLM/LLMService.js +16 -0
  243. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +130 -2
  245. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  246. package/build/dist/Server/Utils/Monitor/IoTDeviceAbsenceSeries.js +81 -0
  247. package/build/dist/Server/Utils/Monitor/IoTDeviceAbsenceSeries.js.map +1 -0
  248. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +18 -7
  249. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  250. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1 -1
  251. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  252. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +25 -10
  253. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  254. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +69 -3
  255. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  256. package/build/dist/Server/Utils/Monitor/MonitorResource.js +76 -30
  257. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  258. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -1
  259. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  260. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +147 -0
  261. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -0
  262. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +167 -0
  263. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -0
  264. package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js +93 -0
  265. package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js.map +1 -0
  266. package/build/dist/Types/AI/AIRunStatus.js +9 -0
  267. package/build/dist/Types/AI/AIRunStatus.js.map +1 -1
  268. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +0 -1
  269. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  270. package/build/dist/Types/LlmLogStatus.js +1 -0
  271. package/build/dist/Types/LlmLogStatus.js.map +1 -1
  272. package/build/dist/Types/Monitor/CriteriaFilter.js +5 -0
  273. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  274. package/build/dist/Types/Monitor/IotAlertTemplates.js +7 -7
  275. package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
  276. package/build/dist/Types/Monitor/LatencyMatrix.js +2 -0
  277. package/build/dist/Types/Monitor/LatencyMatrix.js.map +1 -0
  278. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +2 -2
  279. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  280. package/build/dist/Types/Monitor/MonitorMetricType.js +9 -0
  281. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  282. package/build/dist/Types/Monitor/MonitorStep.js +22 -9
  283. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  284. package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js +36 -0
  285. package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js.map +1 -0
  286. package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js +3 -0
  287. package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js.map +1 -1
  288. package/build/dist/Types/Monitor/MonitorType.js +14 -9
  289. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  290. package/build/dist/Types/Monitor/SnmpMonitor/LldpNeighbor.js +2 -0
  291. package/build/dist/Types/Monitor/SnmpMonitor/LldpNeighbor.js.map +1 -0
  292. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +89 -0
  293. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -0
  294. package/build/dist/Types/Monitor/SnmpMonitor/NetworkTopology.js +2 -0
  295. package/build/dist/Types/Monitor/SnmpMonitor/NetworkTopology.js.map +1 -0
  296. package/build/dist/Types/Monitor/SnmpMonitor/SnmpInterface.js +2 -0
  297. package/build/dist/Types/Monitor/SnmpMonitor/SnmpInterface.js.map +1 -0
  298. package/build/dist/Types/Monitor/SnmpMonitor/SnmpTrap.js +2 -0
  299. package/build/dist/Types/Monitor/SnmpMonitor/SnmpTrap.js.map +1 -0
  300. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +137 -0
  301. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -0
  302. package/build/dist/Types/Permission.js +280 -0
  303. package/build/dist/Types/Permission.js.map +1 -1
  304. package/build/dist/UI/Components/Icon/Icon.js +8 -6
  305. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  306. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +2 -2
  307. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  308. package/build/dist/UI/Components/Tabs/Tabs.js +3 -1
  309. package/build/dist/UI/Components/Tabs/Tabs.js.map +1 -1
  310. package/build/dist/UI/Utils/Navigation.js +11 -1
  311. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  312. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js +17 -20
  313. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js.map +1 -1
  314. package/build/dist/Utils/Monitor/LatencyMatrixUtil.js +89 -0
  315. package/build/dist/Utils/Monitor/LatencyMatrixUtil.js.map +1 -0
  316. package/build/dist/Utils/Monitor/MonitorMetricType.js +68 -1
  317. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  318. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +112 -0
  319. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -0
  320. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  321. package/package.json +1 -1
@@ -207,6 +207,65 @@ describe("SnmpMonitorCriteria.isMonitorInstanceCriteriaFilterMet", () => {
207
207
  expect(result).toBeTruthy();
208
208
  expect(result).toContain("equal to OK");
209
209
  });
210
+
211
+ test("empty OctetString is NOT coerced to numeric 0 for an 'equal to 0' filter", async () => {
212
+ /*
213
+ * Regression: Number("") === 0, so an empty value used to spuriously
214
+ * satisfy a numeric "== 0" criterion. It must fall through to a string
215
+ * comparison ("" !== "0") and not match.
216
+ */
217
+ const criteriaFilter: CriteriaFilter = {
218
+ checkOn: CheckOn.SnmpOidValue,
219
+ filterType: FilterType.EqualTo,
220
+ value: "0",
221
+ snmpMonitorOptions: { oid: PSU_OID },
222
+ };
223
+
224
+ const dataToProcess: ProbeMonitorResponse = buildDataToProcess({
225
+ oidResponses: [
226
+ {
227
+ oid: PSU_OID,
228
+ value: "",
229
+ type: SnmpDataType.OctetString,
230
+ },
231
+ ],
232
+ });
233
+
234
+ const result: string | null =
235
+ await SnmpMonitorCriteria.isMonitorInstanceCriteriaFilterMet({
236
+ dataToProcess,
237
+ criteriaFilter,
238
+ });
239
+
240
+ expect(result).toBeNull();
241
+ });
242
+
243
+ test("whitespace-only OctetString is NOT coerced to numeric 0", async () => {
244
+ const criteriaFilter: CriteriaFilter = {
245
+ checkOn: CheckOn.SnmpOidValue,
246
+ filterType: FilterType.EqualTo,
247
+ value: "0",
248
+ snmpMonitorOptions: { oid: PSU_OID },
249
+ };
250
+
251
+ const dataToProcess: ProbeMonitorResponse = buildDataToProcess({
252
+ oidResponses: [
253
+ {
254
+ oid: PSU_OID,
255
+ value: " ",
256
+ type: SnmpDataType.OctetString,
257
+ },
258
+ ],
259
+ });
260
+
261
+ const result: string | null =
262
+ await SnmpMonitorCriteria.isMonitorInstanceCriteriaFilterMet({
263
+ dataToProcess,
264
+ criteriaFilter,
265
+ });
266
+
267
+ expect(result).toBeNull();
268
+ });
210
269
  });
211
270
 
212
271
  describe("SnmpOidValue guards", () => {
@@ -0,0 +1,113 @@
1
+ import {
2
+ IOT_DEVICE_ID_ATTRIBUTE_KEY,
3
+ buildAbsentIoTDeviceSeries,
4
+ getIoTDeviceAbsenceGroupByKey,
5
+ } from "../../../../Server/Utils/Monitor/IoTDeviceAbsenceSeries";
6
+ import MetricSeriesResult from "../../../../Types/Monitor/MetricMonitor/MetricSeriesResult";
7
+ import MetricSeriesFingerprint from "../../../../Utils/Metrics/MetricSeriesFingerprint";
8
+ import { describe, expect, test } from "@jest/globals";
9
+
10
+ /*
11
+ * The absence-series helpers are what turn a silent registered device
12
+ * into a per-device offline incident — pin down the gating and the
13
+ * synthetic-series shape (which must match what the device's real
14
+ * series would carry so incidents dedupe and auto-resolve).
15
+ */
16
+
17
+ function presentSeries(deviceIds: Array<string>): Array<MetricSeriesResult> {
18
+ return deviceIds.map((id: string) => {
19
+ return {
20
+ fingerprint: MetricSeriesFingerprint.computeFingerprint({
21
+ [IOT_DEVICE_ID_ATTRIBUTE_KEY]: id,
22
+ }),
23
+ labels: { [IOT_DEVICE_ID_ATTRIBUTE_KEY]: id },
24
+ // present series carry samples; the builder only reads labels.
25
+ aggregatedResults: [],
26
+ };
27
+ });
28
+ }
29
+
30
+ describe("getIoTDeviceAbsenceGroupByKey", () => {
31
+ test("returns the key only for a pure device.id group-by", () => {
32
+ expect(getIoTDeviceAbsenceGroupByKey(["device.id"])).toBe("device.id");
33
+ });
34
+
35
+ test.each([
36
+ [[]],
37
+ [["iot.device.type"]],
38
+ [["device.id", "iot.device.type"]],
39
+ [["resource.iot.fleet.name"]],
40
+ ])("returns null for %j", (keys: Array<string>) => {
41
+ expect(getIoTDeviceAbsenceGroupByKey(keys)).toBeNull();
42
+ });
43
+ });
44
+
45
+ describe("buildAbsentIoTDeviceSeries", () => {
46
+ test("emits one empty series per registered-but-absent device", () => {
47
+ const absent: Array<MetricSeriesResult> = buildAbsentIoTDeviceSeries({
48
+ presentSeries: presentSeries(["sensor-1"]),
49
+ expectedDeviceExternalIds: ["sensor-1", "sensor-2", "sensor-3"],
50
+ deviceKey: IOT_DEVICE_ID_ATTRIBUTE_KEY,
51
+ slotCount: 2,
52
+ });
53
+
54
+ expect(absent).toHaveLength(2);
55
+ const ids: Array<string> = absent.map((s: MetricSeriesResult) => {
56
+ return String(s.labels["device.id"]);
57
+ });
58
+ expect(ids.sort()).toEqual(["sensor-2", "sensor-3"]);
59
+
60
+ for (const series of absent) {
61
+ // One empty slot per query+formula so criteria alias resolution lines up.
62
+ expect(series.aggregatedResults).toHaveLength(2);
63
+ for (const slot of series.aggregatedResults) {
64
+ expect(slot.data).toEqual([]);
65
+ }
66
+ // Fingerprint must match what the device's REAL series would carry.
67
+ expect(series.fingerprint).toBe(
68
+ MetricSeriesFingerprint.computeFingerprint(series.labels),
69
+ );
70
+ }
71
+ });
72
+
73
+ test("device ids are compared byte-exact — no canonicalization", () => {
74
+ /*
75
+ * device.id labels are stored verbatim (unlike host.name). A
76
+ * registered id differing only in case is a DIFFERENT device and
77
+ * must be treated as absent; lowercasing would fork the
78
+ * fingerprint from the real series and break dedupe.
79
+ */
80
+ const absent: Array<MetricSeriesResult> = buildAbsentIoTDeviceSeries({
81
+ presentSeries: presentSeries(["Sensor-A"]),
82
+ expectedDeviceExternalIds: ["Sensor-A", "sensor-a"],
83
+ deviceKey: IOT_DEVICE_ID_ATTRIBUTE_KEY,
84
+ slotCount: 1,
85
+ });
86
+
87
+ expect(absent).toHaveLength(1);
88
+ expect(absent[0]?.labels["device.id"]).toBe("sensor-a");
89
+ });
90
+
91
+ test("dedupes duplicate registered ids and skips empties", () => {
92
+ const absent: Array<MetricSeriesResult> = buildAbsentIoTDeviceSeries({
93
+ presentSeries: [],
94
+ expectedDeviceExternalIds: ["sensor-1", "sensor-1", ""],
95
+ deviceKey: IOT_DEVICE_ID_ATTRIBUTE_KEY,
96
+ slotCount: 0, // clamps to 1
97
+ });
98
+
99
+ expect(absent).toHaveLength(1);
100
+ expect(absent[0]?.aggregatedResults).toHaveLength(1);
101
+ });
102
+
103
+ test("returns nothing when every registered device is present", () => {
104
+ const absent: Array<MetricSeriesResult> = buildAbsentIoTDeviceSeries({
105
+ presentSeries: presentSeries(["a", "b"]),
106
+ expectedDeviceExternalIds: ["a", "b"],
107
+ deviceKey: IOT_DEVICE_ID_ATTRIBUTE_KEY,
108
+ slotCount: 1,
109
+ });
110
+
111
+ expect(absent).toHaveLength(0);
112
+ });
113
+ });
@@ -0,0 +1,198 @@
1
+ import MonitorIncident from "../../../../Server/Utils/Monitor/MonitorIncident";
2
+ import MonitorAlert from "../../../../Server/Utils/Monitor/MonitorAlert";
3
+ import Incident from "../../../../Models/DatabaseModels/Incident";
4
+ import Alert from "../../../../Models/DatabaseModels/Alert";
5
+ import MonitorCriteriaInstance from "../../../../Types/Monitor/MonitorCriteriaInstance";
6
+ import Dictionary from "../../../../Types/Dictionary";
7
+ import { describe, expect, it } from "@jest/globals";
8
+
9
+ /*
10
+ * Regression tests for per-series offline/online auto-resolve.
11
+ *
12
+ * Per-series offline monitors (Host / Proxmox / Ceph / IoTDevice) pair
13
+ * an OFFLINE criteria that creates incidents (e.g. Min(device_up) < 1)
14
+ * with a RECOVERY criteria that does not (Min(device_up) >= 1), grouped
15
+ * by a device/host key. Exactly one criteria wins per evaluation tick,
16
+ * and the breaching-series set handed to shouldClose{Incident,Alert} is
17
+ * that winning criteria's per-series matches.
18
+ *
19
+ * On the recovery tick the RECOVERY criteria wins, so its matches are
20
+ * the healthy series — NOT breaches. The bug: membership in that set was
21
+ * treated as "still breaching", so the open offline incident's own
22
+ * fingerprint kept it pinned open forever once no other series was down.
23
+ * The fix only counts membership when the matched criteria actually
24
+ * creates incidents/alerts.
25
+ */
26
+
27
+ const CREATED_CRITERIA_ID: string = "offline-criteria";
28
+ const TEMPLATE_ID: string = "template-1";
29
+ const DEVICE_FP: string = "fp-device-1";
30
+
31
+ const INCIDENT_AUTO_RESOLVE: Dictionary<Array<string>> = {
32
+ [CREATED_CRITERIA_ID]: [TEMPLATE_ID],
33
+ };
34
+ const ALERT_AUTO_RESOLVE: Dictionary<Array<string>> = {
35
+ [CREATED_CRITERIA_ID]: [TEMPLATE_ID],
36
+ };
37
+
38
+ function incident(fingerprint: string): Incident {
39
+ const i: Incident = new Incident();
40
+ i.createdCriteriaId = CREATED_CRITERIA_ID;
41
+ i.createdIncidentTemplateId = TEMPLATE_ID;
42
+ i.seriesFingerprint = fingerprint;
43
+ return i;
44
+ }
45
+
46
+ function alert(fingerprint: string): Alert {
47
+ const a: Alert = new Alert();
48
+ a.createdCriteriaId = CREATED_CRITERIA_ID;
49
+ a.seriesFingerprint = fingerprint;
50
+ return a;
51
+ }
52
+
53
+ function criteria(id: string, creates: boolean): MonitorCriteriaInstance {
54
+ const c: MonitorCriteriaInstance = new MonitorCriteriaInstance();
55
+ c.data!.id = id;
56
+ // Same flag drives both — the templates set createIncidents/createAlerts together.
57
+ c.data!.createIncidents = creates;
58
+ c.data!.createAlerts = creates;
59
+ return c;
60
+ }
61
+
62
+ function shouldCloseIncident(input: Record<string, unknown>): boolean {
63
+ return (
64
+ MonitorIncident as unknown as {
65
+ shouldCloseIncident: (i: Record<string, unknown>) => boolean;
66
+ }
67
+ ).shouldCloseIncident(input);
68
+ }
69
+ function shouldCloseAlert(input: Record<string, unknown>): boolean {
70
+ return (
71
+ MonitorAlert as unknown as {
72
+ shouldCloseAlert: (i: Record<string, unknown>) => boolean;
73
+ }
74
+ ).shouldCloseAlert(input);
75
+ }
76
+
77
+ describe("Per-series offline/online auto-resolve", () => {
78
+ describe("MonitorIncident.shouldCloseIncident", () => {
79
+ it("RESOLVES on the recovery tick even though the recovered series is in the matched (recovery) criteria's set", () => {
80
+ /*
81
+ * The device is back up: the RECOVERY criteria won, its match set
82
+ * contains the now-healthy device. It must NOT keep the incident open.
83
+ */
84
+ expect(
85
+ shouldCloseIncident({
86
+ openIncident: incident(DEVICE_FP),
87
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary:
88
+ INCIDENT_AUTO_RESOLVE,
89
+ criteriaInstance: criteria("recovery-criteria", false),
90
+ breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
91
+ disableSeriesAbsenceResolution: false,
92
+ }),
93
+ ).toBe(true);
94
+ });
95
+
96
+ it("keeps the incident open while the device is still down (offline criteria won, series still breaching)", () => {
97
+ expect(
98
+ shouldCloseIncident({
99
+ openIncident: incident(DEVICE_FP),
100
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary:
101
+ INCIDENT_AUTO_RESOLVE,
102
+ criteriaInstance: criteria(CREATED_CRITERIA_ID, true),
103
+ breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
104
+ disableSeriesAbsenceResolution: false,
105
+ }),
106
+ ).toBe(false);
107
+ });
108
+
109
+ it("resolves when this device recovered but another device is still down (offline criteria won, fp absent)", () => {
110
+ expect(
111
+ shouldCloseIncident({
112
+ openIncident: incident(DEVICE_FP),
113
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary:
114
+ INCIDENT_AUTO_RESOLVE,
115
+ criteriaInstance: criteria(CREATED_CRITERIA_ID, true),
116
+ // Only some OTHER device is still breaching the offline criteria.
117
+ breachingSeriesFingerprints: new Set<string>(["fp-device-2"]),
118
+ disableSeriesAbsenceResolution: false,
119
+ }),
120
+ ).toBe(true);
121
+ });
122
+
123
+ it("does not resolve on recovery when the creating criteria did not opt into auto-resolve", () => {
124
+ expect(
125
+ shouldCloseIncident({
126
+ openIncident: incident(DEVICE_FP),
127
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary: {}, // not configured
128
+ criteriaInstance: criteria("recovery-criteria", false),
129
+ breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
130
+ disableSeriesAbsenceResolution: false,
131
+ }),
132
+ ).toBe(false);
133
+ });
134
+
135
+ it("still respects the event-driven guard (incoming-request) over recovery resolution", () => {
136
+ expect(
137
+ shouldCloseIncident({
138
+ openIncident: incident(DEVICE_FP),
139
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary:
140
+ INCIDENT_AUTO_RESOLVE,
141
+ criteriaInstance: criteria("recovery-criteria", false),
142
+ breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
143
+ disableSeriesAbsenceResolution: true,
144
+ }),
145
+ ).toBe(false);
146
+ });
147
+ });
148
+
149
+ describe("MonitorAlert.shouldCloseAlert", () => {
150
+ it("RESOLVES on the recovery tick even though the recovered series is in the matched (recovery) criteria's set", () => {
151
+ expect(
152
+ shouldCloseAlert({
153
+ openAlert: alert(DEVICE_FP),
154
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: ALERT_AUTO_RESOLVE,
155
+ criteriaInstance: criteria("recovery-criteria", false),
156
+ breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
157
+ disableSeriesAbsenceResolution: false,
158
+ }),
159
+ ).toBe(true);
160
+ });
161
+
162
+ it("keeps the alert open while the device is still down", () => {
163
+ expect(
164
+ shouldCloseAlert({
165
+ openAlert: alert(DEVICE_FP),
166
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: ALERT_AUTO_RESOLVE,
167
+ criteriaInstance: criteria(CREATED_CRITERIA_ID, true),
168
+ breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
169
+ disableSeriesAbsenceResolution: false,
170
+ }),
171
+ ).toBe(false);
172
+ });
173
+
174
+ it("resolves when this device recovered but another is still down", () => {
175
+ expect(
176
+ shouldCloseAlert({
177
+ openAlert: alert(DEVICE_FP),
178
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: ALERT_AUTO_RESOLVE,
179
+ criteriaInstance: criteria(CREATED_CRITERIA_ID, true),
180
+ breachingSeriesFingerprints: new Set<string>(["fp-device-2"]),
181
+ disableSeriesAbsenceResolution: false,
182
+ }),
183
+ ).toBe(true);
184
+ });
185
+
186
+ it("still respects the event-driven guard over recovery resolution", () => {
187
+ expect(
188
+ shouldCloseAlert({
189
+ openAlert: alert(DEVICE_FP),
190
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: ALERT_AUTO_RESOLVE,
191
+ criteriaInstance: criteria("recovery-criteria", false),
192
+ breachingSeriesFingerprints: new Set<string>([DEVICE_FP]),
193
+ disableSeriesAbsenceResolution: true,
194
+ }),
195
+ ).toBe(false);
196
+ });
197
+ });
198
+ });
@@ -120,7 +120,7 @@ describe("MonitorTypeHelper", () => {
120
120
  MonitorType.SSLCertificate,
121
121
  MonitorType.SyntheticMonitor,
122
122
  MonitorType.CustomJavaScriptCode,
123
- MonitorType.SNMP,
123
+ MonitorType.NetworkDevice,
124
124
  MonitorType.DNS,
125
125
  MonitorType.DNSSEC,
126
126
  MonitorType.Domain,
@@ -0,0 +1,111 @@
1
+ import LatencyMatrixUtil from "../../../Utils/Monitor/LatencyMatrixUtil";
2
+ import LatencyMatrix, {
3
+ LatencyMatrixCell,
4
+ } from "../../../Types/Monitor/LatencyMatrix";
5
+
6
+ describe("LatencyMatrixUtil.buildMatrix", () => {
7
+ const now: Date = new Date("2026-07-11T12:00:00Z");
8
+
9
+ it("builds a dense grid seeded with no-data cells", () => {
10
+ const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
11
+ monitors: [{ id: "m1", name: "Ping A" }],
12
+ probes: [
13
+ { id: "p1", name: "US East" },
14
+ { id: "p2", name: "EU West" },
15
+ ],
16
+ results: [],
17
+ now,
18
+ });
19
+
20
+ expect(matrix.monitors).toHaveLength(1);
21
+ expect(matrix.probes).toHaveLength(2);
22
+ expect(matrix.cells["m1"]!["p1"]!.hasData).toBe(false);
23
+ expect(matrix.cells["m1"]!["p2"]!.hasData).toBe(false);
24
+ });
25
+
26
+ it("fills latency, online state, and age from the latest step", () => {
27
+ const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
28
+ monitors: [{ id: "m1", name: "Ping A" }],
29
+ probes: [{ id: "p1", name: "US East" }],
30
+ results: [
31
+ {
32
+ monitorId: "m1",
33
+ probeId: "p1",
34
+ lastMonitoringLog: {
35
+ step1: {
36
+ responseTimeInMs: 42,
37
+ isOnline: true,
38
+ monitoredAt: "2026-07-11T11:59:00Z",
39
+ },
40
+ },
41
+ },
42
+ ],
43
+ now,
44
+ });
45
+
46
+ const cell: LatencyMatrixCell = matrix.cells["m1"]!["p1"]!;
47
+ expect(cell.hasData).toBe(true);
48
+ expect(cell.latencyInMs).toBe(42);
49
+ expect(cell.isOnline).toBe(true);
50
+ expect(cell.ageInSeconds).toBe(60);
51
+ });
52
+
53
+ it("picks the most recently monitored step across multiple steps", () => {
54
+ const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
55
+ monitors: [{ id: "m1", name: "Ping A" }],
56
+ probes: [{ id: "p1", name: "US East" }],
57
+ results: [
58
+ {
59
+ monitorId: "m1",
60
+ probeId: "p1",
61
+ lastMonitoringLog: {
62
+ older: {
63
+ responseTimeInMs: 100,
64
+ isOnline: true,
65
+ monitoredAt: "2026-07-11T10:00:00Z",
66
+ },
67
+ newer: {
68
+ responseTimeInMs: 25,
69
+ isOnline: true,
70
+ monitoredAt: "2026-07-11T11:59:30Z",
71
+ },
72
+ },
73
+ },
74
+ ],
75
+ now,
76
+ });
77
+
78
+ expect(matrix.cells["m1"]!["p1"]!.latencyInMs).toBe(25);
79
+ });
80
+
81
+ it("ignores results for unknown monitor/probe pairs", () => {
82
+ const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
83
+ monitors: [{ id: "m1", name: "Ping A" }],
84
+ probes: [{ id: "p1", name: "US East" }],
85
+ results: [
86
+ {
87
+ monitorId: "ghost",
88
+ probeId: "p1",
89
+ lastMonitoringLog: {
90
+ step1: { responseTimeInMs: 5, monitoredAt: now.toISOString() },
91
+ },
92
+ },
93
+ ],
94
+ now,
95
+ });
96
+
97
+ expect(matrix.cells["m1"]!["p1"]!.hasData).toBe(false);
98
+ expect(matrix.cells["ghost"]).toBeUndefined();
99
+ });
100
+
101
+ it("treats an empty log as no data", () => {
102
+ const matrix: LatencyMatrix = LatencyMatrixUtil.buildMatrix({
103
+ monitors: [{ id: "m1", name: "Ping A" }],
104
+ probes: [{ id: "p1", name: "US East" }],
105
+ results: [{ monitorId: "m1", probeId: "p1", lastMonitoringLog: {} }],
106
+ now,
107
+ });
108
+
109
+ expect(matrix.cells["m1"]!["p1"]!.hasData).toBe(false);
110
+ });
111
+ });
@@ -1,4 +1,13 @@
1
1
  enum AIRunStatus {
2
+ /*
3
+ * Durable intent: the run has been recorded but no worker has claimed it
4
+ * yet. Queued runs survive pod restarts — the enqueueing pod tries to
5
+ * process immediately, and the queue poller picks up whatever is left
6
+ * (claims are CAS-guarded, so double-processing is impossible). Not
7
+ * terminal, not consuming compute; the queue's own TTL expires runs that
8
+ * sit here too long to still be useful.
9
+ */
10
+ Queued = "Queued",
2
11
  Running = "Running",
3
12
  /*
4
13
  * The run paused mid-turn to wait for the user to approve pending tool
@@ -27,7 +27,6 @@ export enum EntityFilterModelType {
27
27
  AlertState = "AlertState",
28
28
  MonitorStatus = "MonitorStatus",
29
29
  Monitor = "Monitor",
30
- Service = "Service",
31
30
  Label = "Label",
32
31
  KubernetesCluster = "KubernetesCluster",
33
32
  DockerHost = "DockerHost",
@@ -1,5 +1,6 @@
1
1
  import ObjectID from "../../ObjectID";
2
2
  import DashboardComponentType from "../DashboardComponentType";
3
+ import DashboardChartType from "../Chart/ChartType";
3
4
  import BaseComponent from "./DashboardBaseComponent";
4
5
 
5
6
  export default interface DashboardLogChartComponent extends BaseComponent {
@@ -7,12 +8,16 @@ export default interface DashboardLogChartComponent extends BaseComponent {
7
8
  componentId: ObjectID;
8
9
  arguments: {
9
10
  title?: string | undefined;
10
- serviceIds?: Array<string> | undefined;
11
+ chartType?: DashboardChartType | undefined;
11
12
  severityFilters?: Array<string> | undefined;
12
13
  bodyContains?: string | undefined;
13
14
  /*
14
- * Exact attribute matches in the log-search syntax used by Log Stream,
15
- * for example: @service.name:checkout @deployment.environment:production.
15
+ * Exact attribute matches stored by the structured key/value editor.
16
+ */
17
+ attributeFilters?: Record<string, string | number | boolean> | undefined;
18
+ /*
19
+ * Legacy log-search syntax retained as a read-only fallback for widgets
20
+ * saved before the structured attribute editor was introduced.
16
21
  */
17
22
  attributeFilterQuery?: string | undefined;
18
23
  };
@@ -2,6 +2,7 @@ enum LlmLogStatus {
2
2
  Success = "Success",
3
3
  Error = "Error",
4
4
  InsufficientBalance = "Insufficient Balance",
5
+ BudgetExceeded = "Budget Exceeded",
5
6
  }
6
7
 
7
8
  export default LlmLogStatus;
@@ -71,6 +71,10 @@ export enum CheckOn {
71
71
  SnmpOidExists = "SNMP OID Exists",
72
72
  SnmpResponseTime = "SNMP Response Time (in ms)",
73
73
  SnmpIsOnline = "SNMP Device Is Online",
74
+ SnmpInterfaceIsDown = "SNMP Interface Is Down",
75
+ SnmpTrapReceived = "SNMP Trap Received (Trap OID)",
76
+ SnmpInterfaceUtilizationPercent = "SNMP Interface Utilization (in %)",
77
+ SnmpInterfaceErrorsPerSecond = "SNMP Interface Errors (per second)",
74
78
 
75
79
  // DNS monitors.
76
80
  DnsResponseTime = "DNS Response Time (in ms)",
@@ -287,6 +291,7 @@ export class CriteriaFilterUtil {
287
291
  if (
288
292
  checkOn === CheckOn.IsOnline ||
289
293
  checkOn === CheckOn.SnmpIsOnline ||
294
+ checkOn === CheckOn.SnmpInterfaceIsDown ||
290
295
  checkOn === CheckOn.DnsIsOnline ||
291
296
  checkOn === CheckOn.DomainIsExpired ||
292
297
  checkOn === CheckOn.DnssecChainValid ||
@@ -3,7 +3,12 @@ import MonitorStep from "./MonitorStep";
3
3
  import MonitorCriteria from "./MonitorCriteria";
4
4
  import MonitorCriteriaInstance from "./MonitorCriteriaInstance";
5
5
  import FilterCondition from "../Filter/FilterCondition";
6
- import { CheckOn, FilterType, EvaluateOverTimeType } from "./CriteriaFilter";
6
+ import {
7
+ CheckOn,
8
+ FilterType,
9
+ EvaluateOverTimeType,
10
+ NoDataPolicy,
11
+ } from "./CriteriaFilter";
7
12
  import MonitorStepIoTMonitor from "./MonitorStepIoTMonitor";
8
13
  import RollingTime from "../RollingTime/RollingTime";
9
14
  import MetricsAggregationType from "../Metrics/MetricsAggregationType";
@@ -102,6 +107,16 @@ export function buildIoTOfflineCriteriaInstance(args: {
102
107
  incidentDescription?: string;
103
108
  criteriaName?: string;
104
109
  criteriaDescription?: string;
110
+ /*
111
+ * Evaluate an empty (no data) series as 0 instead of skipping it.
112
+ * This is what lets REGISTERED devices that go completely silent
113
+ * trip the criteria: monitor evaluation injects an empty synthetic
114
+ * series per registered-but-silent device, TreatAsZero folds it to
115
+ * 0, and e.g. Min(iot_device_up) < 1 fires. Only the Device Offline
116
+ * template opts in — treating no-data as zero on a battery or
117
+ * temperature threshold would false-alarm for silent devices.
118
+ */
119
+ treatNoDataAsZero?: boolean;
105
120
  }): MonitorCriteriaInstance {
106
121
  const instance: MonitorCriteriaInstance = new MonitorCriteriaInstance();
107
122
 
@@ -122,6 +137,9 @@ export function buildIoTOfflineCriteriaInstance(args: {
122
137
  metricMonitorOptions: {
123
138
  metricAggregationType: EvaluateOverTimeType.AnyValue,
124
139
  metricAlias: args.metricAlias,
140
+ ...(args.treatNoDataAsZero
141
+ ? { onNoDataPolicy: NoDataPolicy.TreatAsZero }
142
+ : {}),
125
143
  },
126
144
  value: args.value,
127
145
  },
@@ -356,10 +374,11 @@ const deviceOfflineTemplate: IoTAlertTemplate = {
356
374
  filterType: FilterType.LessThan,
357
375
  value: 1,
358
376
  incidentTitle: `[IoT] Device Offline - ${args.monitorName}`,
359
- incidentDescription: `An IoT device is reporting as down (iot_device_up = 0). The device is unreachable, powered off, or has lost connectivity to its gateway. Check the root cause for the affected device id, verify the device's power and network state, and confirm its gateway is forwarding telemetry.`,
377
+ incidentDescription: `An IoT device is reporting as down (iot_device_up = 0) or has stopped reporting entirely. The device is unreachable, powered off, or has lost connectivity to its gateway. Check the root cause for the affected device id, verify the device's power and network state, and confirm its gateway is forwarding telemetry.`,
360
378
  criteriaName: "Device Offline - iot_device_up < 1",
361
379
  criteriaDescription:
362
- "Triggers when any device reports iot_device_up below 1 over the monitoring window.",
380
+ "Triggers when any device reports iot_device_up below 1 over the monitoring window, or when a registered device goes silent.",
381
+ treatNoDataAsZero: true,
363
382
  }),
364
383
  onlineCriteriaInstance: buildIoTOnlineCriteriaInstance({
365
384
  onlineMonitorStatusId: args.onlineMonitorStatusId,
@@ -0,0 +1,27 @@
1
+ /*
2
+ * A probes × targets latency grid. Each cell is the latest response time a
3
+ * probe measured for a monitor, so operators can see at a glance which
4
+ * probe locations are slow to which targets. Built from each monitor's
5
+ * per-probe last-check snapshot; no new data collection.
6
+ */
7
+ export interface LatencyMatrixAxisItem {
8
+ id: string;
9
+ name: string;
10
+ }
11
+
12
+ export interface LatencyMatrixCell {
13
+ monitorId: string;
14
+ probeId: string;
15
+ hasData: boolean;
16
+ latencyInMs?: number | undefined;
17
+ isOnline?: boolean | undefined;
18
+ // Age of the measurement in seconds, so the UI can dim stale cells.
19
+ ageInSeconds?: number | undefined;
20
+ }
21
+
22
+ export default interface LatencyMatrix {
23
+ monitors: Array<LatencyMatrixAxisItem>;
24
+ probes: Array<LatencyMatrixAxisItem>;
25
+ // Keyed cells[monitorId][probeId].
26
+ cells: Record<string, Record<string, LatencyMatrixCell>>;
27
+ }
@@ -415,7 +415,7 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
415
415
  return monitorCriteriaInstance;
416
416
  }
417
417
 
418
- if (arg.monitorType === MonitorType.SNMP) {
418
+ if (arg.monitorType === MonitorType.NetworkDevice) {
419
419
  const monitorCriteriaInstance: MonitorCriteriaInstance =
420
420
  new MonitorCriteriaInstance();
421
421
 
@@ -616,7 +616,7 @@ export default class MonitorCriteriaInstance extends DatabaseProperty {
616
616
  };
617
617
  }
618
618
 
619
- if (arg.monitorType === MonitorType.SNMP) {
619
+ if (arg.monitorType === MonitorType.NetworkDevice) {
620
620
  monitorCriteriaInstance.data = {
621
621
  id: ObjectID.generate().toString(),
622
622
  monitorStatusId: arg.monitorStatusId,