@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
@@ -41,6 +41,7 @@ export interface LLMCompletionRequest {
41
41
  messages: Array<LLMMessage>;
42
42
  temperature?: number | undefined;
43
43
  maxTokens?: number | undefined;
44
+ additionalParams?: JSONObject | undefined;
44
45
  tools?: Array<LLMToolDefinition> | undefined;
45
46
  llmProviderConfig: LLMProviderConfig;
46
47
  }
@@ -226,6 +227,26 @@ export default class LLMService {
226
227
  data["tools"] = this.toOpenAITools(request.tools);
227
228
  }
228
229
 
230
+ // Provider-configured overrides are applied last so they win over defaults.
231
+ if (request.additionalParams) {
232
+ Object.assign(data, request.additionalParams);
233
+ }
234
+
235
+ /*
236
+ * OpenAI's newer model families (gpt-5, o1, o3, ...) reject the legacy
237
+ * `max_tokens` parameter and require `max_completion_tokens` instead; the
238
+ * two are mutually exclusive. When a provider opts into
239
+ * `max_completion_tokens` via additionalParams, drop the default
240
+ * `max_tokens` so the request is accepted. Legacy OpenAI-compatible
241
+ * backends (Ollama, vLLM, LocalAI, ...) keep receiving `max_tokens`.
242
+ */
243
+ if (
244
+ data["max_completion_tokens"] !== undefined &&
245
+ data["max_tokens"] !== undefined
246
+ ) {
247
+ delete data["max_tokens"];
248
+ }
249
+
229
250
  return data;
230
251
  }
231
252
 
@@ -5,9 +5,11 @@ import {
5
5
  CriteriaFilter,
6
6
  FilterType,
7
7
  } from "../../../../Types/Monitor/CriteriaFilter";
8
+ import SnmpInterface from "../../../../Types/Monitor/SnmpMonitor/SnmpInterface";
8
9
  import SnmpMonitorResponse, {
9
10
  SnmpOidResponse,
10
11
  } from "../../../../Types/Monitor/SnmpMonitor/SnmpMonitorResponse";
12
+ import SnmpTrap from "../../../../Types/Monitor/SnmpMonitor/SnmpTrap";
11
13
  import ProbeMonitorResponse from "../../../../Types/Probe/ProbeMonitorResponse";
12
14
  import EvaluateOverTime from "./EvaluateOverTime";
13
15
  import CaptureSpan from "../../Telemetry/CaptureSpan";
@@ -28,6 +30,63 @@ export default class SnmpMonitorCriteria {
28
30
  const snmpResponse: SnmpMonitorResponse | undefined =
29
31
  dataToProcess.snmpResponse;
30
32
 
33
+ /*
34
+ * Event/check separation. Trap responses are evaluated ONLY against
35
+ * trap criteria; polled check responses never match trap criteria.
36
+ * This keeps a trap from misfiring "is online" style filters (it has
37
+ * no check data) and keeps every poll from re-firing trap criteria.
38
+ */
39
+ const snmpTrap: SnmpTrap | undefined = dataToProcess.snmpTrapResponse;
40
+
41
+ if (input.criteriaFilter.checkOn === CheckOn.SnmpTrapReceived) {
42
+ if (!snmpTrap) {
43
+ return null;
44
+ }
45
+
46
+ const expectedOid: string = String(threshold || "").trim();
47
+
48
+ if (!expectedOid) {
49
+ return null;
50
+ }
51
+
52
+ const trapOid: string = snmpTrap.trapOid;
53
+ let isMatch: boolean = false;
54
+
55
+ switch (input.criteriaFilter.filterType) {
56
+ case FilterType.EqualTo:
57
+ isMatch = trapOid === expectedOid;
58
+ break;
59
+ case FilterType.NotEqualTo:
60
+ isMatch = trapOid !== expectedOid;
61
+ break;
62
+ case FilterType.Contains:
63
+ isMatch = trapOid.includes(expectedOid);
64
+ break;
65
+ case FilterType.NotContains:
66
+ isMatch = !trapOid.includes(expectedOid);
67
+ break;
68
+ case FilterType.StartsWith:
69
+ isMatch = trapOid.startsWith(expectedOid);
70
+ break;
71
+ case FilterType.EndsWith:
72
+ isMatch = trapOid.endsWith(expectedOid);
73
+ break;
74
+ default:
75
+ isMatch = false;
76
+ }
77
+
78
+ if (isMatch) {
79
+ return `SNMP trap ${trapOid} received from ${snmpTrap.sourceIpAddress}.`;
80
+ }
81
+
82
+ return null;
83
+ }
84
+
85
+ if (snmpTrap) {
86
+ // Trap events never evaluate check-based criteria.
87
+ return null;
88
+ }
89
+
31
90
  let overTimeValue: Array<number | boolean> | number | boolean | undefined =
32
91
  undefined;
33
92
 
@@ -91,6 +150,108 @@ export default class SnmpMonitorCriteria {
91
150
  });
92
151
  }
93
152
 
153
+ // Check if any monitored interface is down (admin-up but oper-down)
154
+ if (input.criteriaFilter.checkOn === CheckOn.SnmpInterfaceIsDown) {
155
+ const interfaces: Array<SnmpInterface> | undefined =
156
+ snmpResponse?.interfaces;
157
+
158
+ if (!interfaces || interfaces.length === 0) {
159
+ return null;
160
+ }
161
+
162
+ /*
163
+ * Administratively disabled interfaces are intentionally down and
164
+ * never count as failures.
165
+ */
166
+ const downInterfaces: Array<SnmpInterface> = interfaces.filter(
167
+ (snmpInterface: SnmpInterface) => {
168
+ return (
169
+ snmpInterface.isAdministrativelyUp &&
170
+ !snmpInterface.isOperationallyUp
171
+ );
172
+ },
173
+ );
174
+
175
+ const isTrueFilter: boolean =
176
+ input.criteriaFilter.filterType === FilterType.True;
177
+ const isFalseFilter: boolean =
178
+ input.criteriaFilter.filterType === FilterType.False;
179
+
180
+ if (downInterfaces.length > 0 && isTrueFilter) {
181
+ const names: string = downInterfaces
182
+ .slice(0, 5)
183
+ .map((snmpInterface: SnmpInterface) => {
184
+ return snmpInterface.name;
185
+ })
186
+ .join(", ");
187
+ return `${downInterfaces.length} interface(s) down: ${names}${
188
+ downInterfaces.length > 5 ? ", …" : ""
189
+ }.`;
190
+ }
191
+
192
+ if (downInterfaces.length === 0 && isFalseFilter) {
193
+ return "All administratively enabled interfaces are up.";
194
+ }
195
+
196
+ return null;
197
+ }
198
+
199
+ // Check the busiest interface's utilization
200
+ if (
201
+ input.criteriaFilter.checkOn === CheckOn.SnmpInterfaceUtilizationPercent
202
+ ) {
203
+ threshold = CompareCriteria.convertToNumber(threshold);
204
+
205
+ if (threshold === null || threshold === undefined) {
206
+ return null;
207
+ }
208
+
209
+ const utilizations: Array<number> = (snmpResponse?.interfaces || [])
210
+ .map((snmpInterface: SnmpInterface) => {
211
+ return snmpInterface.utilizationPercent;
212
+ })
213
+ .filter((value: number | undefined): value is number => {
214
+ return typeof value === "number";
215
+ });
216
+
217
+ if (utilizations.length === 0) {
218
+ return null;
219
+ }
220
+
221
+ return CompareCriteria.compareCriteriaNumbers({
222
+ value: Math.max(...utilizations),
223
+ threshold: threshold as number,
224
+ criteriaFilter: input.criteriaFilter,
225
+ });
226
+ }
227
+
228
+ // Check the worst interface's error rate
229
+ if (input.criteriaFilter.checkOn === CheckOn.SnmpInterfaceErrorsPerSecond) {
230
+ threshold = CompareCriteria.convertToNumber(threshold);
231
+
232
+ if (threshold === null || threshold === undefined) {
233
+ return null;
234
+ }
235
+
236
+ const errorRates: Array<number> = (snmpResponse?.interfaces || [])
237
+ .map((snmpInterface: SnmpInterface) => {
238
+ return snmpInterface.errorsPerSecond;
239
+ })
240
+ .filter((value: number | undefined): value is number => {
241
+ return typeof value === "number";
242
+ });
243
+
244
+ if (errorRates.length === 0) {
245
+ return null;
246
+ }
247
+
248
+ return CompareCriteria.compareCriteriaNumbers({
249
+ value: Math.max(...errorRates),
250
+ threshold: threshold as number,
251
+ criteriaFilter: input.criteriaFilter,
252
+ });
253
+ }
254
+
94
255
  // Check if a specific OID exists (returns a value)
95
256
  if (input.criteriaFilter.checkOn === CheckOn.SnmpOidExists) {
96
257
  const oid: string | undefined =
@@ -145,8 +306,15 @@ export default class SnmpMonitorCriteria {
145
306
 
146
307
  const oidValue: string | number = oidResponse.value;
147
308
 
148
- // Numeric comparison
149
- if (typeof oidValue === "number" || !isNaN(Number(oidValue))) {
309
+ /*
310
+ * Numeric comparison only when the value is genuinely numeric. Guard
311
+ * against empty/whitespace OctetStrings, which Number("") coerces to 0
312
+ * and would spuriously satisfy a "== 0" criterion.
313
+ */
314
+ const isNumeric: boolean =
315
+ typeof oidValue === "number" ||
316
+ (String(oidValue).trim() !== "" && !isNaN(Number(oidValue)));
317
+ if (isNumeric) {
150
318
  const numericValue: number =
151
319
  typeof oidValue === "number" ? oidValue : Number(oidValue);
152
320
  const numericThreshold: number | null =
@@ -0,0 +1,101 @@
1
+ import AggregatedResult from "../../../Types/BaseDatabase/AggregatedResult";
2
+ import { JSONObject } from "../../../Types/JSON";
3
+ import MetricSeriesResult from "../../../Types/Monitor/MetricMonitor/MetricSeriesResult";
4
+ import MetricSeriesFingerprint from "../../../Utils/Metrics/MetricSeriesFingerprint";
5
+
6
+ /*
7
+ * Pure helpers backing per-device "went silent" detection for IoT
8
+ * Device monitors — the IoT analogue of HostAbsenceSeries (which also
9
+ * supplies the shared monitorStepOptsIntoNoDataDetection and
10
+ * queriesScopeHostSubset gates; both are entity-agnostic).
11
+ *
12
+ * A group-by-device metric query only returns a series for devices
13
+ * that emitted rows in the evaluation window — a device that stopped
14
+ * reporting simply has no row, so its absence is invisible to the
15
+ * criteria evaluator. These helpers synthesize an empty "no data"
16
+ * series for every REGISTERED device (IoTDeviceCredential) missing
17
+ * from the current window, so the per-series NoDataPolicy path fires
18
+ * one correctly-labeled alert per silent device. Kept pure (no DB) so
19
+ * the gating and series construction are unit-testable; the worker
20
+ * supplies the expected-device list.
21
+ *
22
+ * Unlike hosts there is NO recency aging: registration is an explicit
23
+ * expected-list, so a registered-but-silent device alerts until its
24
+ * credential is disabled or deleted — that is the designed semantic.
25
+ *
26
+ * Device ids are handled VERBATIM: device.id datapoint labels are
27
+ * stored byte-exact (unlike host.name, which is canonicalized at
28
+ * ingest), so canonicalizing here would fork the fingerprint from the
29
+ * device's real series and break incident dedupe/auto-resolve.
30
+ */
31
+
32
+ // The datapoint label that identifies a device within a fleet.
33
+ export const IOT_DEVICE_ID_ATTRIBUTE_KEY: string = "device.id";
34
+
35
+ /**
36
+ * If the monitor is grouped by exactly the device-id label, return
37
+ * that group-by key; otherwise null. Absent-device synthesis only
38
+ * makes sense for a pure per-device group-by.
39
+ */
40
+ export function getIoTDeviceAbsenceGroupByKey(
41
+ groupByAttributeKeys: Array<string>,
42
+ ): string | null {
43
+ if (!groupByAttributeKeys || groupByAttributeKeys.length !== 1) {
44
+ return null;
45
+ }
46
+ const key: string = groupByAttributeKeys[0]!;
47
+ return key === IOT_DEVICE_ID_ATTRIBUTE_KEY ? key : null;
48
+ }
49
+
50
+ /**
51
+ * Build synthetic "no data" series for every registered device absent
52
+ * from the current window's series breakdown. Each synthetic series
53
+ * has empty aggregated-result slots (one per query + formula,
54
+ * matching how present series are shaped) so the criteria evaluator's
55
+ * NoDataPolicy path fires for it, and labels/fingerprint identical to
56
+ * what the device's present series would carry so the resulting
57
+ * incident dedupes and auto-resolves when the device returns.
58
+ */
59
+ export function buildAbsentIoTDeviceSeries(input: {
60
+ presentSeries: Array<MetricSeriesResult>;
61
+ expectedDeviceExternalIds: Array<string>;
62
+ deviceKey: string;
63
+ slotCount: number;
64
+ }): Array<MetricSeriesResult> {
65
+ const presentDevices: Set<string> = new Set<string>();
66
+ for (const series of input.presentSeries) {
67
+ const raw: unknown = series.labels?.[input.deviceKey];
68
+ if (raw === undefined || raw === null || String(raw) === "") {
69
+ continue;
70
+ }
71
+ presentDevices.add(String(raw));
72
+ }
73
+
74
+ const slotCount: number = Math.max(input.slotCount, 1);
75
+ const seen: Set<string> = new Set<string>();
76
+ const absentSeries: Array<MetricSeriesResult> = [];
77
+
78
+ for (const externalId of input.expectedDeviceExternalIds) {
79
+ const identifier: string = String(externalId);
80
+ if (!identifier || presentDevices.has(identifier) || seen.has(identifier)) {
81
+ continue;
82
+ }
83
+ seen.add(identifier);
84
+
85
+ const labels: JSONObject = { [input.deviceKey]: identifier };
86
+ const aggregatedResults: Array<AggregatedResult> = Array.from(
87
+ { length: slotCount },
88
+ (): AggregatedResult => {
89
+ return { data: [] };
90
+ },
91
+ );
92
+
93
+ absentSeries.push({
94
+ fingerprint: MetricSeriesFingerprint.computeFingerprint(labels),
95
+ labels,
96
+ aggregatedResults,
97
+ });
98
+ }
99
+
100
+ return absentSeries;
101
+ }
@@ -749,9 +749,21 @@ export default class MonitorAlert {
749
749
  input.breachingSeriesFingerprints !== undefined &&
750
750
  openSeriesFingerprint
751
751
  ) {
752
- const stillBreaching: boolean = input.breachingSeriesFingerprints.has(
753
- openSeriesFingerprint,
754
- );
752
+ /*
753
+ * The breaching set is the matched criteria's per-series matches.
754
+ * On a recovery tick the matched criteria is the RECOVERY criteria
755
+ * and its matches are healthy series, not breaches; counting them
756
+ * would pin the open offline alert open forever. Membership only
757
+ * counts as still-breaching when the matched criteria actually
758
+ * creates alerts (createAlerts=false recovery criteria contributes
759
+ * no breaches, letting the per-series alert auto-resolve).
760
+ */
761
+ const matchedCriteriaCreatesAlerts: boolean =
762
+ input.criteriaInstance?.data?.createAlerts === true;
763
+
764
+ const stillBreaching: boolean =
765
+ matchedCriteriaCreatesAlerts &&
766
+ input.breachingSeriesFingerprints.has(openSeriesFingerprint);
755
767
 
756
768
  if (stillBreaching) {
757
769
  return false;
@@ -775,7 +775,7 @@ ${contextBlock}
775
775
  }
776
776
  }
777
777
 
778
- if (input.monitor.monitorType === MonitorType.SNMP) {
778
+ if (input.monitor.monitorType === MonitorType.NetworkDevice) {
779
779
  const snmpMonitorResult: string | null =
780
780
  await SnmpMonitorCriteria.isMonitorInstanceCriteriaFilterMet({
781
781
  dataToProcess: input.dataToProcess,
@@ -1141,9 +1141,25 @@ export default class MonitorIncident {
1141
1141
  input.breachingSeriesFingerprints !== undefined &&
1142
1142
  openSeriesFingerprint
1143
1143
  ) {
1144
- const stillBreaching: boolean = input.breachingSeriesFingerprints.has(
1145
- openSeriesFingerprint,
1146
- );
1144
+ /*
1145
+ * The breaching set is the matched criteria's per-series matches.
1146
+ * Only ONE criteria wins per evaluation tick, so on a recovery
1147
+ * tick the matched criteria is the RECOVERY criteria (e.g.
1148
+ * Min(iot_device_up) >= 1) and its "matches" are healthy series —
1149
+ * NOT breaches. Treating them as breaching would leave the open
1150
+ * offline incident's fingerprint in the set and pin it open
1151
+ * forever once no other series is down. So membership only counts
1152
+ * as still-breaching when the matched criteria actually creates
1153
+ * incidents (an offline/breach criteria); a recovery criteria
1154
+ * (createIncidents=false) contributes no breaches and lets the
1155
+ * per-series incident auto-resolve.
1156
+ */
1157
+ const matchedCriteriaCreatesIncidents: boolean =
1158
+ input.criteriaInstance?.data?.createIncidents === true;
1159
+
1160
+ const stillBreaching: boolean =
1161
+ matchedCriteriaCreatesIncidents &&
1162
+ input.breachingSeriesFingerprints.has(openSeriesFingerprint);
1147
1163
 
1148
1164
  if (stillBreaching) {
1149
1165
  return false;
@@ -17,6 +17,7 @@ import CapturedMetric from "../../../Types/Monitor/CustomCodeMonitor/CapturedMet
17
17
  import HttpPhaseTimings from "../../../Types/Monitor/HttpPhaseTimings";
18
18
  import MonitorMetricType from "../../../Types/Monitor/MonitorMetricType";
19
19
  import PingMonitorResponse from "../../../Types/Monitor/PingMonitor/PingMonitorResponse";
20
+ import SnmpInterface from "../../../Types/Monitor/SnmpMonitor/SnmpInterface";
20
21
  import ProbeMonitorResponse from "../../../Types/Probe/ProbeMonitorResponse";
21
22
  import ServerMonitorResponse from "../../../Types/Monitor/ServerMonitor/ServerMonitorResponse";
22
23
  import SyntheticMonitorResponse from "../../../Types/Monitor/SyntheticMonitors/SyntheticMonitorResponse";
@@ -889,6 +890,92 @@ export default class MonitorMetricUtil {
889
890
  metricNameServiceNameMap[MonitorMetricType.ResponseTime] = metricType;
890
891
  }
891
892
 
893
+ const snmpInterfaces: Array<SnmpInterface> | undefined = (
894
+ data.dataToProcess as ProbeMonitorResponse
895
+ ).snmpResponse?.interfaces;
896
+
897
+ if (snmpInterfaces && snmpInterfaces.length > 0) {
898
+ /*
899
+ * Cap per-check interface series to keep a single check from writing
900
+ * unbounded rows (large routers can expose thousands of
901
+ * subinterfaces). Same approach as the custom-metric cap below.
902
+ */
903
+ const interfacesToEmit: Array<SnmpInterface> = snmpInterfaces.slice(
904
+ 0,
905
+ 200,
906
+ );
907
+
908
+ if (interfacesToEmit.length < snmpInterfaces.length) {
909
+ logger.warn(
910
+ `Monitor ${data.monitorId.toString()}: emitting metrics for first ${interfacesToEmit.length} of ${snmpInterfaces.length} SNMP interfaces`,
911
+ );
912
+ }
913
+
914
+ for (const snmpInterface of interfacesToEmit) {
915
+ const extraAttributes: JSONObject = {
916
+ probeId: (
917
+ data.dataToProcess as ProbeMonitorResponse
918
+ ).probeId.toString(),
919
+ interfaceName: snmpInterface.name,
920
+ interfaceIndex: snmpInterface.interfaceIndex.toString(),
921
+ };
922
+
923
+ const interfaceMetrics: Array<{
924
+ metricName: MonitorMetricType;
925
+ value: number | undefined;
926
+ description: string;
927
+ unit: string;
928
+ }> = [
929
+ {
930
+ metricName: MonitorMetricType.SnmpInterfaceOperStatus,
931
+ value: snmpInterface.isOperationallyUp ? 1 : 0,
932
+ description: "SNMP interface operational status (1 up, 0 down)",
933
+ unit: "",
934
+ },
935
+ {
936
+ metricName: MonitorMetricType.SnmpInterfaceInBitsPerSecond,
937
+ value: snmpInterface.inBitsPerSecond,
938
+ description: "SNMP interface inbound bandwidth",
939
+ unit: "bps",
940
+ },
941
+ {
942
+ metricName: MonitorMetricType.SnmpInterfaceOutBitsPerSecond,
943
+ value: snmpInterface.outBitsPerSecond,
944
+ description: "SNMP interface outbound bandwidth",
945
+ unit: "bps",
946
+ },
947
+ {
948
+ metricName: MonitorMetricType.SnmpInterfaceUtilizationPercent,
949
+ value: snmpInterface.utilizationPercent,
950
+ description: "SNMP interface utilization",
951
+ unit: "%",
952
+ },
953
+ {
954
+ metricName: MonitorMetricType.SnmpInterfaceErrorsPerSecond,
955
+ value: snmpInterface.errorsPerSecond,
956
+ description: "SNMP interface errors per second",
957
+ unit: "errors/s",
958
+ },
959
+ ];
960
+
961
+ for (const interfaceMetric of interfaceMetrics) {
962
+ await this.pushMonitorMetric({
963
+ projectId: data.projectId,
964
+ monitorId: data.monitorId,
965
+ monitorName: data.monitorName,
966
+ probeName: data.probeName,
967
+ metricName: interfaceMetric.metricName,
968
+ value: interfaceMetric.value,
969
+ description: interfaceMetric.description,
970
+ unit: interfaceMetric.unit,
971
+ extraAttributes: extraAttributes,
972
+ metricRows: metricRows,
973
+ metricNameServiceNameMap: metricNameServiceNameMap,
974
+ });
975
+ }
976
+ }
977
+ }
978
+
892
979
  if ((data.dataToProcess as ProbeMonitorResponse).httpTimings) {
893
980
  const httpTimings: HttpPhaseTimings = (
894
981
  data.dataToProcess as ProbeMonitorResponse
@@ -5,10 +5,13 @@ import logger from "../Logger";
5
5
  import MonitorCriteriaEvaluator from "./MonitorCriteriaEvaluator";
6
6
  import MonitorLogUtil from "./MonitorLogUtil";
7
7
  import MonitorMetricUtil from "./MonitorMetricUtil";
8
+ import NetworkInventoryUtil from "./NetworkInventoryUtil";
9
+ import SnmpInterfaceRateUtil from "./SnmpInterfaceRateUtil";
8
10
  import DataToProcess from "./DataToProcess";
9
11
  import SortOrder from "../../../Types/BaseDatabase/SortOrder";
10
12
  import Dictionary from "../../../Types/Dictionary";
11
13
  import BadDataException from "../../../Types/Exception/BadDataException";
14
+ import { JSONObject } from "../../../Types/JSON";
12
15
  import Semaphore, { SemaphoreMutex } from "../../Infrastructure/Semaphore";
13
16
  import IncomingMonitorRequest from "../../../Types/Monitor/IncomingMonitor/IncomingMonitorRequest";
14
17
  import MonitorCriteria from "../../../Types/Monitor/MonitorCriteria";
@@ -237,6 +240,16 @@ export default class MonitorResourceUtil {
237
240
  let probeName: string | undefined = undefined;
238
241
  const monitorName: string | undefined = monitor.name || undefined;
239
242
 
243
+ /*
244
+ * SNMP trap responses are event-driven, not check results. They are
245
+ * evaluated ONLY against trap criteria; they must not overwrite the
246
+ * last check's counters, participate in probe agreement, or reset the
247
+ * monitor to its default status when no criteria matches.
248
+ */
249
+ const isSnmpTrapEvent: boolean = Boolean(
250
+ (dataToProcess as ProbeMonitorResponse).snmpTrapResponse,
251
+ );
252
+
240
253
  // save the last log to MonitorProbe.
241
254
 
242
255
  // get last log. We do this because there are many monitoring steps and we need to store those.
@@ -275,26 +288,58 @@ export default class MonitorResourceUtil {
275
288
 
276
289
  probeName = monitorProbe.probe?.name || undefined;
277
290
 
278
- await MonitorProbeService.updateOneBy({
279
- query: {
280
- monitorId: monitor.id!,
281
- probeId: (dataToProcess as ProbeMonitorResponse).probeId!,
282
- },
283
- data: {
284
- lastMonitoringLog: {
285
- ...(monitorProbe.lastMonitoringLog || {}),
286
- [(
287
- dataToProcess as ProbeMonitorResponse
288
- ).monitorStepId.toString()]: {
289
- ...JSON.parse(JSON.stringify(dataToProcess)),
290
- monitoredAt: OneUptimeDate.getCurrentDate(),
291
- },
292
- } as any,
293
- },
294
- props: {
295
- isRoot: true,
296
- },
297
- });
291
+ /*
292
+ * SNMP interface rates (bandwidth, utilization, errors/sec) are
293
+ * deltas against the previous check's counters — computed here,
294
+ * while the previous log is still available, so the computed
295
+ * values flow into metrics, criteria, and the stored log below.
296
+ */
297
+ if (monitor.monitorType === MonitorType.NetworkDevice) {
298
+ SnmpInterfaceRateUtil.attachInterfaceRates({
299
+ probeMonitorResponse: dataToProcess as ProbeMonitorResponse,
300
+ previousStepLog: (
301
+ monitorProbe.lastMonitoringLog as JSONObject | undefined
302
+ )?.[
303
+ (dataToProcess as ProbeMonitorResponse).monitorStepId.toString()
304
+ ] as JSONObject | undefined,
305
+ });
306
+
307
+ /*
308
+ * Sync the NetworkDevice/NetworkInterface inventory from the
309
+ * walk, then prune the response to monitored interfaces so
310
+ * criteria and metrics ignore muted ports. Trap events carry
311
+ * no walk data — nothing to sync.
312
+ */
313
+ if (!isSnmpTrapEvent) {
314
+ await NetworkInventoryUtil.updateFromWalk({
315
+ monitor: monitor,
316
+ dataToProcess: dataToProcess as ProbeMonitorResponse,
317
+ });
318
+ }
319
+ }
320
+
321
+ if (!isSnmpTrapEvent) {
322
+ await MonitorProbeService.updateOneBy({
323
+ query: {
324
+ monitorId: monitor.id!,
325
+ probeId: (dataToProcess as ProbeMonitorResponse).probeId!,
326
+ },
327
+ data: {
328
+ lastMonitoringLog: {
329
+ ...(monitorProbe.lastMonitoringLog || {}),
330
+ [(
331
+ dataToProcess as ProbeMonitorResponse
332
+ ).monitorStepId.toString()]: {
333
+ ...JSON.parse(JSON.stringify(dataToProcess)),
334
+ monitoredAt: OneUptimeDate.getCurrentDate(),
335
+ },
336
+ } as any,
337
+ },
338
+ props: {
339
+ isRoot: true,
340
+ },
341
+ });
342
+ }
298
343
  }
299
344
  }
300
345
 
@@ -603,7 +648,12 @@ export default class MonitorResourceUtil {
603
648
  // Check probe agreement for probe-based monitors
604
649
  if (
605
650
  monitor.monitorType &&
606
- MonitorTypeHelper.isProbableMonitor(monitor.monitorType)
651
+ MonitorTypeHelper.isProbableMonitor(monitor.monitorType) &&
652
+ /*
653
+ * Traps arrive on exactly one probe — other probes' polled state
654
+ * cannot corroborate them, so agreement would always veto the trap.
655
+ */
656
+ !isSnmpTrapEvent
607
657
  ) {
608
658
  const probeAgreementResult: ProbeAgreementResult =
609
659
  await MonitorResourceUtil.checkProbeAgreement({
@@ -874,6 +924,12 @@ export default class MonitorResourceUtil {
874
924
  });
875
925
  } else if (
876
926
  !response.criteriaMetId &&
927
+ /*
928
+ * A trap that matches no criteria is simply ignored — it must not
929
+ * reset the monitor to its default status (the polled checks own
930
+ * the monitor's state).
931
+ */
932
+ !isSnmpTrapEvent &&
877
933
  monitorSteps.data.defaultMonitorStatusId &&
878
934
  monitor.currentMonitorStatusId?.toString() !==
879
935
  monitorSteps.data.defaultMonitorStatusId.toString()
@@ -245,7 +245,7 @@ export default class MonitorTemplateUtil {
245
245
  } as JSONObject;
246
246
  }
247
247
 
248
- if (data.monitorType === MonitorType.SNMP) {
248
+ if (data.monitorType === MonitorType.NetworkDevice) {
249
249
  const snmpResponse: SnmpMonitorResponse | undefined = (
250
250
  data.dataToProcess as ProbeMonitorResponse
251
251
  ).snmpResponse;