@oneuptime/common 11.4.1 → 11.5.1

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 (324) 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 +26 -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/MoreMenu/MoreMenu.tsx +61 -2
  112. package/UI/Components/Tabs/Tabs.tsx +10 -1
  113. package/UI/Utils/Navigation.ts +10 -1
  114. package/Utils/Dashboard/Components/DashboardLogChartComponent.ts +16 -21
  115. package/Utils/Monitor/LatencyMatrixUtil.ts +162 -0
  116. package/Utils/Monitor/MonitorMetricType.ts +71 -1
  117. package/Utils/Monitor/NetworkTopologyUtil.ts +159 -0
  118. package/Utils/Telemetry/EntityRelationship.ts +11 -0
  119. package/build/dist/Models/DatabaseModels/AIRun.js +52 -0
  120. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  121. package/build/dist/Models/DatabaseModels/AlertSeverity.js +6 -0
  122. package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
  123. package/build/dist/Models/DatabaseModels/IncidentSeverity.js +6 -0
  124. package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
  125. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  126. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  127. package/build/dist/Models/DatabaseModels/IoTDeviceCredential.js +493 -0
  128. package/build/dist/Models/DatabaseModels/IoTDeviceCredential.js.map +1 -0
  129. package/build/dist/Models/DatabaseModels/LlmLog.js +58 -0
  130. package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -1
  131. package/build/dist/Models/DatabaseModels/LlmProvider.js +33 -0
  132. package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
  133. package/build/dist/Models/DatabaseModels/NetworkDevice.js +1426 -0
  134. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -0
  135. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +738 -0
  136. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -0
  137. package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js +522 -0
  138. package/build/dist/Models/DatabaseModels/NetworkDeviceLabelRule.js.map +1 -0
  139. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js +603 -0
  140. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerRule.js.map +1 -0
  141. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js +503 -0
  142. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerTeam.js.map +1 -0
  143. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js +502 -0
  144. package/build/dist/Models/DatabaseModels/NetworkDeviceOwnerUser.js.map +1 -0
  145. package/build/dist/Models/DatabaseModels/NetworkInterface.js +589 -0
  146. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -0
  147. package/build/dist/Models/DatabaseModels/Project.js +147 -0
  148. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  149. package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js +57 -0
  150. package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js.map +1 -1
  151. package/build/dist/Server/API/AIInvestigationAPI.js +95 -55
  152. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  153. package/build/dist/Server/API/AlertAPI.js +5 -0
  154. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  155. package/build/dist/Server/API/IncidentAPI.js +10 -0
  156. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  157. package/build/dist/Server/API/IncidentEpisodeAPI.js +5 -0
  158. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  159. package/build/dist/Server/API/LlmProviderAPI.js +5 -7
  160. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  161. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +5 -0
  162. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  163. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.js +12 -0
  164. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783650000000-AddAdditionalParamsToLlmProvider.js.map +1 -0
  165. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.js +14 -0
  166. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783695782697-AddCacheTokenColumnsToLlmLog.js.map +1 -0
  167. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.js +18 -0
  168. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783701585317-AddAlertInvestigationGating.js.map +1 -0
  169. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.js +12 -0
  170. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783702431535-AddAiDailyAutonomousTokenLimitToProject.js.map +1 -0
  171. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.js +51 -0
  172. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783720000000-AddNetworkDeviceTables.js.map +1 -0
  173. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.js +12 -0
  174. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783721121260-AddAttemptCountToAIRun.js.map +1 -0
  175. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.js +101 -0
  176. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783730000000-AddNetworkDeviceOwnersAndRules.js.map +1 -0
  177. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.js +18 -0
  178. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783740000000-AddNetworkDeviceDiscoveryScan.js.map +1 -0
  179. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.js +12 -0
  180. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783750000000-AddLldpNeighborsToNetworkDevice.js.map +1 -0
  181. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.js +14 -0
  182. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783760576655-AddInvestigationTuningToProject.js.map +1 -0
  183. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.js +16 -0
  184. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783762505482-AddTelemetryEntityRelationshipMetrics.js.map +1 -0
  185. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.js +38 -0
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783780000000-AddIoTDeviceCredentialTable.js.map +1 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.js +22 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783790000000-AddSnmpV3AuthColumnsToNetworkDevice.js.map +1 -0
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +26 -0
  190. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  191. package/build/dist/Server/Services/AIRunService.js +33 -0
  192. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  193. package/build/dist/Server/Services/AIService.js +82 -9
  194. package/build/dist/Server/Services/AIService.js.map +1 -1
  195. package/build/dist/Server/Services/IncidentService.js +14 -25
  196. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  197. package/build/dist/Server/Services/Index.js +14 -0
  198. package/build/dist/Server/Services/Index.js.map +1 -1
  199. package/build/dist/Server/Services/IoTDeviceCredentialService.js +321 -0
  200. package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -0
  201. package/build/dist/Server/Services/IoTDeviceService.js +49 -15
  202. package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
  203. package/build/dist/Server/Services/LlmLogService.js +29 -0
  204. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  205. package/build/dist/Server/Services/LlmProviderService.js +3 -0
  206. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  207. package/build/dist/Server/Services/MonitorService.js +2 -1
  208. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  209. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +9 -0
  210. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -0
  211. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +166 -0
  212. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -0
  213. package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js +13 -0
  214. package/build/dist/Server/Services/NetworkDeviceLabelRuleService.js.map +1 -0
  215. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +186 -0
  216. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -0
  217. package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js +13 -0
  218. package/build/dist/Server/Services/NetworkDeviceOwnerRuleService.js.map +1 -0
  219. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js +9 -0
  220. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js.map +1 -0
  221. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js +9 -0
  222. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js.map +1 -0
  223. package/build/dist/Server/Services/NetworkDeviceService.js +52 -0
  224. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -0
  225. package/build/dist/Server/Services/NetworkInterfaceService.js +9 -0
  226. package/build/dist/Server/Services/NetworkInterfaceService.js.map +1 -0
  227. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +22 -0
  228. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
  229. package/build/dist/Server/Services/TelemetryEntityService.js +64 -2
  230. package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
  231. package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js +189 -9
  232. package/build/dist/Server/Utils/AI/Sentinel/AlertInvestigationRunner.js.map +1 -1
  233. package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js +84 -17
  234. package/build/dist/Server/Utils/AI/Sentinel/IncidentInvestigationRunner.js.map +1 -1
  235. package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js +428 -0
  236. package/build/dist/Server/Utils/AI/Sentinel/InvestigationQueue.js.map +1 -0
  237. package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js +63 -47
  238. package/build/dist/Server/Utils/AI/Sentinel/SentinelInvestigationEngine.js.map +1 -1
  239. package/build/dist/Server/Utils/AI/Toolbox/Index.js +2 -1
  240. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  241. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +300 -0
  242. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -1
  243. package/build/dist/Server/Utils/LLM/LLMService.js +16 -0
  244. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  245. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +130 -2
  246. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  247. package/build/dist/Server/Utils/Monitor/IoTDeviceAbsenceSeries.js +81 -0
  248. package/build/dist/Server/Utils/Monitor/IoTDeviceAbsenceSeries.js.map +1 -0
  249. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +18 -7
  250. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  251. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1 -1
  252. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  253. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +25 -10
  254. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  255. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +69 -3
  256. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  257. package/build/dist/Server/Utils/Monitor/MonitorResource.js +76 -30
  258. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  259. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -1
  260. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  261. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +147 -0
  262. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -0
  263. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +167 -0
  264. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -0
  265. package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js +93 -0
  266. package/build/dist/Server/Utils/Monitor/SnmpInterfaceRateUtil.js.map +1 -0
  267. package/build/dist/Types/AI/AIRunStatus.js +9 -0
  268. package/build/dist/Types/AI/AIRunStatus.js.map +1 -1
  269. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +0 -1
  270. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  271. package/build/dist/Types/LlmLogStatus.js +1 -0
  272. package/build/dist/Types/LlmLogStatus.js.map +1 -1
  273. package/build/dist/Types/Monitor/CriteriaFilter.js +5 -0
  274. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  275. package/build/dist/Types/Monitor/IotAlertTemplates.js +7 -7
  276. package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
  277. package/build/dist/Types/Monitor/LatencyMatrix.js +2 -0
  278. package/build/dist/Types/Monitor/LatencyMatrix.js.map +1 -0
  279. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +2 -2
  280. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  281. package/build/dist/Types/Monitor/MonitorMetricType.js +9 -0
  282. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  283. package/build/dist/Types/Monitor/MonitorStep.js +22 -9
  284. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  285. package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js +36 -0
  286. package/build/dist/Types/Monitor/MonitorStepNetworkDeviceMonitor.js.map +1 -0
  287. package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js +3 -0
  288. package/build/dist/Types/Monitor/MonitorStepSnmpMonitor.js.map +1 -1
  289. package/build/dist/Types/Monitor/MonitorType.js +14 -9
  290. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  291. package/build/dist/Types/Monitor/SnmpMonitor/LldpNeighbor.js +2 -0
  292. package/build/dist/Types/Monitor/SnmpMonitor/LldpNeighbor.js.map +1 -0
  293. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +89 -0
  294. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -0
  295. package/build/dist/Types/Monitor/SnmpMonitor/NetworkTopology.js +2 -0
  296. package/build/dist/Types/Monitor/SnmpMonitor/NetworkTopology.js.map +1 -0
  297. package/build/dist/Types/Monitor/SnmpMonitor/SnmpInterface.js +2 -0
  298. package/build/dist/Types/Monitor/SnmpMonitor/SnmpInterface.js.map +1 -0
  299. package/build/dist/Types/Monitor/SnmpMonitor/SnmpTrap.js +2 -0
  300. package/build/dist/Types/Monitor/SnmpMonitor/SnmpTrap.js.map +1 -0
  301. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +137 -0
  302. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -0
  303. package/build/dist/Types/Permission.js +280 -0
  304. package/build/dist/Types/Permission.js.map +1 -1
  305. package/build/dist/UI/Components/Icon/Icon.js +8 -6
  306. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  307. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +2 -2
  308. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  309. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +44 -4
  310. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  311. package/build/dist/UI/Components/Tabs/Tabs.js +3 -1
  312. package/build/dist/UI/Components/Tabs/Tabs.js.map +1 -1
  313. package/build/dist/UI/Utils/Navigation.js +11 -1
  314. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  315. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js +17 -20
  316. package/build/dist/Utils/Dashboard/Components/DashboardLogChartComponent.js.map +1 -1
  317. package/build/dist/Utils/Monitor/LatencyMatrixUtil.js +89 -0
  318. package/build/dist/Utils/Monitor/LatencyMatrixUtil.js.map +1 -0
  319. package/build/dist/Utils/Monitor/MonitorMetricType.js +68 -1
  320. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  321. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +112 -0
  322. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -0
  323. package/build/dist/Utils/Telemetry/EntityRelationship.js.map +1 -1
  324. package/package.json +1 -1
@@ -348,38 +348,81 @@ export class Service extends DatabaseService<Model> {
348
348
  }
349
349
 
350
350
  /**
351
- * Hard-delete all devices in a fleet whose last scrape is older
352
- * than olderThan. Returns the number of deleted rows. Only called by
353
- * the cleanup worker for fleets that are still connected — a
354
- * disconnected fleet keeps its last-known inventory.
351
+ * Age out devices in a fleet whose last scrape is older than
352
+ * olderThan. Only called by the cleanup worker for fleets that are
353
+ * still connected a disconnected fleet keeps its last-known
354
+ * inventory.
355
+ *
356
+ * REGISTERED devices (a matching IoTDeviceCredential row on
357
+ * fleet + externalId, kind-agnostic) are flipped to Down instead of
358
+ * deleted: registration marks the device as expected, so a silent
359
+ * device must stay visible in the inventory as offline. Unregistered
360
+ * devices are hard-deleted as before (the inventory is a projection
361
+ * of what is actively reporting).
362
+ *
363
+ * The UPDATE deliberately does NOT touch lastSeenAt: reconnect
364
+ * recovery relies on the bulkUpsert dominance guard comparing a
365
+ * fresh scrape against the old timestamp, so the next scrape flips
366
+ * isUp back to true automatically.
355
367
  */
356
368
  @CaptureSpan()
357
369
  public async deleteStaleForFleet(data: {
358
370
  iotFleetId: ObjectID;
359
371
  olderThan: Date;
360
- }): Promise<number> {
361
- const result: Array<{ affected?: number }> | { affected?: number } =
362
- await this.getRepository().manager.query(
363
- `DELETE FROM "IoTDevice" WHERE "iotFleetId" = $1 AND "lastSeenAt" < $2`,
364
- [data.iotFleetId.toString(), data.olderThan],
365
- );
366
-
367
- // Postgres driver returns [rows, affected] for DELETE — normalize.
368
- let affected: number = 0;
369
- if (Array.isArray(result) && result.length >= 2) {
370
- const second: unknown = (result as Array<unknown>)[1];
371
- if (typeof second === "number") {
372
- affected = second;
372
+ }): Promise<{ deleted: number; markedOffline: number }> {
373
+ // Postgres driver returns [rows, affected] for UPDATE/DELETE normalize.
374
+ const affectedOf: (result: unknown) => number = (
375
+ result: unknown,
376
+ ): number => {
377
+ if (Array.isArray(result) && result.length >= 2) {
378
+ const second: unknown = (result as Array<unknown>)[1];
379
+ if (typeof second === "number") {
380
+ return second;
381
+ }
373
382
  }
374
- }
383
+ return 0;
384
+ };
385
+
386
+ /*
387
+ * Registered = a live credential on the same PROJECT + fleet +
388
+ * device id (kind-agnostic — one credential covers every kind the
389
+ * device reports). The projectId correlation is defense-in-depth
390
+ * against a credential row that names another project's fleet.
391
+ */
392
+ const registeredSubquery: string = `SELECT 1 FROM "IoTDeviceCredential" c WHERE c."projectId" = "IoTDevice"."projectId" AND c."iotFleetId" = "IoTDevice"."iotFleetId" AND c."externalId" = "IoTDevice"."externalId" AND c."deletedAt" IS NULL`;
393
+
394
+ /*
395
+ * A device whose iot.device.kind label drifts mints a second
396
+ * inventory row (identity is projectId+iotFleetId+kind+externalId).
397
+ * Without this guard the stale old-kind row would be registered
398
+ * (same externalId) and pinned as Offline forever. "Shadowed" =
399
+ * a fresher row exists for the same (fleet, externalId) under a
400
+ * different kind — keep only the freshest, let shadows self-heal.
401
+ */
402
+ const shadowedSubquery: string = `SELECT 1 FROM "IoTDevice" d2 WHERE d2."iotFleetId" = "IoTDevice"."iotFleetId" AND d2."externalId" = "IoTDevice"."externalId" AND d2."kind" <> "IoTDevice"."kind" AND d2."lastSeenAt" > "IoTDevice"."lastSeenAt" AND d2."deletedAt" IS NULL`;
403
+
404
+ const params: Array<unknown> = [data.iotFleetId.toString(), data.olderThan];
405
+
406
+ const updateResult: unknown = await this.getRepository().manager.query(
407
+ `UPDATE "IoTDevice" SET "isUp" = false, "updatedAt" = now() WHERE "iotFleetId" = $1 AND "lastSeenAt" < $2 AND "isUp" IS DISTINCT FROM false AND EXISTS (${registeredSubquery}) AND NOT EXISTS (${shadowedSubquery})`,
408
+ params,
409
+ );
410
+
411
+ const deleteResult: unknown = await this.getRepository().manager.query(
412
+ `DELETE FROM "IoTDevice" WHERE "iotFleetId" = $1 AND "lastSeenAt" < $2 AND (NOT EXISTS (${registeredSubquery}) OR EXISTS (${shadowedSubquery}))`,
413
+ params,
414
+ );
415
+
416
+ const deleted: number = affectedOf(deleteResult);
417
+ const markedOffline: number = affectedOf(updateResult);
375
418
 
376
- if (affected > STALE_DELETE_WARN_THRESHOLD) {
419
+ if (deleted > STALE_DELETE_WARN_THRESHOLD) {
377
420
  logger.warn(
378
- `IoTDevice cleanup deleted ${affected} stale rows for fleet ${data.iotFleetId.toString()} — larger than expected; investigate agent health.`,
421
+ `IoTDevice cleanup deleted ${deleted} stale rows for fleet ${data.iotFleetId.toString()} — larger than expected; investigate agent health.`,
379
422
  );
380
423
  }
381
424
 
382
- return affected;
425
+ return { deleted, markedOffline };
383
426
  }
384
427
 
385
428
  /**
@@ -1,6 +1,8 @@
1
1
  import DatabaseService from "./DatabaseService";
2
2
  import Model from "../../Models/DatabaseModels/LlmLog";
3
3
  import { IsBillingEnabled } from "../EnvironmentConfig";
4
+ import ObjectID from "../../Types/ObjectID";
5
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
4
6
 
5
7
  export class Service extends DatabaseService<Model> {
6
8
  public constructor() {
@@ -9,6 +11,30 @@ export class Service extends DatabaseService<Model> {
9
11
  this.hardDeleteItemsOlderThanInDays("createdAt", 3);
10
12
  }
11
13
  }
14
+
15
+ /*
16
+ * Sum of totalTokens this project has consumed for the given features since
17
+ * the given time — one SQL aggregate, used on the hot path of the daily
18
+ * autonomous-budget check (G4).
19
+ */
20
+ @CaptureSpan()
21
+ public async getTotalTokensUsedSince(data: {
22
+ projectId: ObjectID;
23
+ since: Date;
24
+ features: Array<string>;
25
+ }): Promise<number> {
26
+ if (data.features.length === 0) {
27
+ return 0;
28
+ }
29
+
30
+ const rows: Array<{ total: string | number | null }> =
31
+ await this.getRepository().manager.query(
32
+ `SELECT COALESCE(SUM("totalTokens"), 0) AS "total" FROM "LlmLog" WHERE "projectId" = $1 AND "createdAt" >= $2 AND "feature" = ANY($3) AND "deletedAt" IS NULL`,
33
+ [data.projectId.toString(), data.since, data.features],
34
+ );
35
+
36
+ return Number(rows[0]?.total || 0);
37
+ }
12
38
  }
13
39
 
14
40
  export default new Service();
@@ -115,6 +115,7 @@ export class Service extends DatabaseService<Model> {
115
115
  apiKey: true,
116
116
  baseUrl: true,
117
117
  modelName: true,
118
+ additionalParams: true,
118
119
  isGlobalLlm: true,
119
120
  costPerMillionTokensInUSDCents: true,
120
121
  },
@@ -140,6 +141,7 @@ export class Service extends DatabaseService<Model> {
140
141
  apiKey: true,
141
142
  baseUrl: true,
142
143
  modelName: true,
144
+ additionalParams: true,
143
145
  isGlobalLlm: true,
144
146
  costPerMillionTokensInUSDCents: true,
145
147
  },
@@ -180,6 +182,7 @@ export class Service extends DatabaseService<Model> {
180
182
  apiKey: true,
181
183
  baseUrl: true,
182
184
  modelName: true,
185
+ additionalParams: true,
183
186
  isGlobalLlm: true,
184
187
  projectId: true,
185
188
  costPerMillionTokensInUSDCents: true,
@@ -121,7 +121,10 @@ export class Service extends DatabaseService<Model> {
121
121
  }
122
122
 
123
123
  // For SNMP monitors, use the hostname from snmpMonitor config
124
- if (monitorType === MonitorType.SNMP && firstStep?.data?.snmpMonitor) {
124
+ if (
125
+ monitorType === MonitorType.NetworkDevice &&
126
+ firstStep?.data?.snmpMonitor
127
+ ) {
125
128
  monitorDestination = firstStep.data.snmpMonitor.hostname || "";
126
129
  const port: number = firstStep.data.snmpMonitor.port || 161;
127
130
  if (monitorDestination && port) {
@@ -0,0 +1,10 @@
1
+ import DatabaseService from "./DatabaseService";
2
+ import Model from "../../Models/DatabaseModels/NetworkDeviceDiscoveryScan";
3
+
4
+ export class Service extends DatabaseService<Model> {
5
+ public constructor() {
6
+ super(Model);
7
+ }
8
+ }
9
+
10
+ export default new Service();
@@ -0,0 +1,204 @@
1
+ import Label from "../../Models/DatabaseModels/Label";
2
+ import NetworkDevice from "../../Models/DatabaseModels/NetworkDevice";
3
+ import NetworkDeviceLabelRule from "../../Models/DatabaseModels/NetworkDeviceLabelRule";
4
+ import NetworkDeviceLabelRuleService from "./NetworkDeviceLabelRuleService";
5
+ import NetworkDeviceService from "./NetworkDeviceService";
6
+ import ObjectID from "../../Types/ObjectID";
7
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
8
+ import logger, { LogAttributes } from "../Utils/Logger";
9
+
10
+ class NetworkDeviceLabelRuleEngineServiceClass {
11
+ /**
12
+ * Evaluates NetworkDeviceLabelRule rows for the given network device and attaches matched
13
+ * labels to it. The union is deduped against labels already on the network device
14
+ * before insert to avoid PK conflicts on the join table.
15
+ */
16
+ @CaptureSpan()
17
+ public async applyRulesToNetworkDevice(
18
+ networkDevice: NetworkDevice,
19
+ ): Promise<void> {
20
+ if (!networkDevice.id || !networkDevice.projectId) {
21
+ return;
22
+ }
23
+
24
+ try {
25
+ const rules: Array<NetworkDeviceLabelRule> =
26
+ await NetworkDeviceLabelRuleService.findBy({
27
+ query: {
28
+ projectId: networkDevice.projectId,
29
+ isEnabled: true,
30
+ },
31
+ props: { isRoot: true },
32
+ select: {
33
+ _id: true,
34
+ name: true,
35
+ networkDeviceLabels: { _id: true },
36
+ networkDeviceNamePattern: true,
37
+ networkDeviceDescriptionPattern: true,
38
+ labelsToAdd: { _id: true },
39
+ },
40
+ limit: 100,
41
+ skip: 0,
42
+ });
43
+
44
+ if (rules.length === 0) {
45
+ return;
46
+ }
47
+
48
+ const networkDeviceWithDetails: NetworkDevice | null =
49
+ await NetworkDeviceService.findOneById({
50
+ id: networkDevice.id,
51
+ select: {
52
+ name: true,
53
+ description: true,
54
+ labels: { _id: true },
55
+ },
56
+ props: { isRoot: true },
57
+ });
58
+
59
+ if (!networkDeviceWithDetails) {
60
+ return;
61
+ }
62
+
63
+ const labelIdsToAdd: Set<string> = new Set();
64
+
65
+ for (const rule of rules) {
66
+ const matches: boolean = this.doesNetworkDeviceMatchRule(
67
+ networkDeviceWithDetails,
68
+ rule,
69
+ );
70
+ if (!matches) {
71
+ continue;
72
+ }
73
+ for (const label of rule.labelsToAdd || []) {
74
+ if (label.id) {
75
+ labelIdsToAdd.add(label.id.toString());
76
+ }
77
+ }
78
+ }
79
+
80
+ if (labelIdsToAdd.size === 0) {
81
+ return;
82
+ }
83
+
84
+ const existingLabelIds: Set<string> = new Set(
85
+ (networkDeviceWithDetails.labels || [])
86
+ .map((l: Label) => {
87
+ return l.id?.toString() || "";
88
+ })
89
+ .filter((id: string) => {
90
+ return id !== "";
91
+ }),
92
+ );
93
+
94
+ const newLabelIds: Array<string> = Array.from(labelIdsToAdd).filter(
95
+ (id: string) => {
96
+ return !existingLabelIds.has(id);
97
+ },
98
+ );
99
+ if (newLabelIds.length === 0) {
100
+ return;
101
+ }
102
+
103
+ await NetworkDeviceService.getRepository()
104
+ .createQueryBuilder()
105
+ .relation(NetworkDevice, "labels")
106
+ .of(networkDevice.id.toString())
107
+ .add(newLabelIds);
108
+
109
+ /*
110
+ * Sync in-memory networkDevice.labels so a downstream owner-rule engine in
111
+ * the same onCreateSuccess chain can match on rule-added labels.
112
+ */
113
+ const mergedLabelIds: Set<string> = new Set([
114
+ ...existingLabelIds,
115
+ ...newLabelIds,
116
+ ]);
117
+ networkDevice.labels = Array.from(mergedLabelIds).map((id: string) => {
118
+ const label: Label = new Label();
119
+ label.id = new ObjectID(id);
120
+ return label;
121
+ });
122
+
123
+ logger.debug(
124
+ `NetworkDeviceLabelRuleEngine attached ${newLabelIds.length} labels to network device ${networkDevice.id}`,
125
+ { projectId: networkDevice.projectId.toString() } as LogAttributes,
126
+ );
127
+ } catch (error) {
128
+ logger.error(`Error applying network device label rules: ${error}`, {
129
+ projectId: networkDevice.projectId?.toString(),
130
+ networkDeviceId: networkDevice.id?.toString(),
131
+ } as LogAttributes);
132
+ }
133
+ }
134
+
135
+ private doesNetworkDeviceMatchRule(
136
+ networkDevice: NetworkDevice,
137
+ rule: NetworkDeviceLabelRule,
138
+ ): boolean {
139
+ if (rule.networkDeviceLabels && rule.networkDeviceLabels.length > 0) {
140
+ if (!networkDevice.labels || networkDevice.labels.length === 0) {
141
+ return false;
142
+ }
143
+ const ruleLabelIds: Array<string> = rule.networkDeviceLabels.map(
144
+ (l: Label) => {
145
+ return l.id?.toString() || "";
146
+ },
147
+ );
148
+ const labelIds: Array<string> = networkDevice.labels.map((l: Label) => {
149
+ return l.id?.toString() || "";
150
+ });
151
+ if (
152
+ !ruleLabelIds.some((id: string) => {
153
+ return labelIds.includes(id);
154
+ })
155
+ ) {
156
+ return false;
157
+ }
158
+ }
159
+
160
+ if (
161
+ rule.networkDeviceNamePattern &&
162
+ (!networkDevice.name ||
163
+ !this.testRegex(
164
+ rule.networkDeviceNamePattern,
165
+ networkDevice.name,
166
+ rule,
167
+ ))
168
+ ) {
169
+ return false;
170
+ }
171
+
172
+ if (
173
+ rule.networkDeviceDescriptionPattern &&
174
+ (!networkDevice.description ||
175
+ !this.testRegex(
176
+ rule.networkDeviceDescriptionPattern,
177
+ networkDevice.description,
178
+ rule,
179
+ ))
180
+ ) {
181
+ return false;
182
+ }
183
+
184
+ return true;
185
+ }
186
+
187
+ private testRegex(
188
+ pattern: string,
189
+ value: string,
190
+ rule: NetworkDeviceLabelRule,
191
+ ): boolean {
192
+ try {
193
+ const regex: RegExp = new RegExp(pattern, "i");
194
+ return regex.test(value);
195
+ } catch {
196
+ logger.warn(
197
+ `Invalid regex in network device label rule ${rule.id}: ${pattern}`,
198
+ );
199
+ return false;
200
+ }
201
+ }
202
+ }
203
+
204
+ export default new NetworkDeviceLabelRuleEngineServiceClass();
@@ -0,0 +1,14 @@
1
+ import DatabaseService from "./DatabaseService";
2
+ import Model from "../../Models/DatabaseModels/NetworkDeviceLabelRule";
3
+ import { IsBillingEnabled } from "../EnvironmentConfig";
4
+
5
+ export class Service extends DatabaseService<Model> {
6
+ public constructor() {
7
+ super(Model);
8
+ if (IsBillingEnabled) {
9
+ this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365);
10
+ }
11
+ }
12
+ }
13
+
14
+ export default new Service();
@@ -0,0 +1,222 @@
1
+ import Label from "../../Models/DatabaseModels/Label";
2
+ import NetworkDevice from "../../Models/DatabaseModels/NetworkDevice";
3
+ import NetworkDeviceOwnerRule from "../../Models/DatabaseModels/NetworkDeviceOwnerRule";
4
+ import NetworkDeviceOwnerUser from "../../Models/DatabaseModels/NetworkDeviceOwnerUser";
5
+ import NetworkDeviceOwnerTeam from "../../Models/DatabaseModels/NetworkDeviceOwnerTeam";
6
+ import NetworkDeviceOwnerRuleService from "./NetworkDeviceOwnerRuleService";
7
+ import NetworkDeviceOwnerUserService from "./NetworkDeviceOwnerUserService";
8
+ import NetworkDeviceOwnerTeamService from "./NetworkDeviceOwnerTeamService";
9
+ import NetworkDeviceService from "./NetworkDeviceService";
10
+ import ObjectID from "../../Types/ObjectID";
11
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
12
+ import logger, { LogAttributes } from "../Utils/Logger";
13
+
14
+ class NetworkDeviceOwnerRuleEngineServiceClass {
15
+ /**
16
+ * Evaluates NetworkDeviceOwnerRule rows for the given network device and adds matched
17
+ * owner users / teams via NetworkDeviceOwnerUserService / NetworkDeviceOwnerTeamService. Rules
18
+ * with notifyOwners set notify the added owners; rules with notifyOwners off
19
+ * add silently.
20
+ */
21
+ @CaptureSpan()
22
+ public async applyRulesToNetworkDevice(
23
+ networkDevice: NetworkDevice,
24
+ ): Promise<void> {
25
+ if (!networkDevice.id || !networkDevice.projectId) {
26
+ return;
27
+ }
28
+
29
+ try {
30
+ const rules: Array<NetworkDeviceOwnerRule> =
31
+ await NetworkDeviceOwnerRuleService.findBy({
32
+ query: {
33
+ projectId: networkDevice.projectId,
34
+ isEnabled: true,
35
+ },
36
+ props: { isRoot: true },
37
+ select: {
38
+ _id: true,
39
+ name: true,
40
+ notifyOwners: true,
41
+ networkDeviceLabels: { _id: true },
42
+ networkDeviceNamePattern: true,
43
+ networkDeviceDescriptionPattern: true,
44
+ ownerUsers: { _id: true },
45
+ ownerTeams: { _id: true },
46
+ },
47
+ limit: 100,
48
+ skip: 0,
49
+ });
50
+
51
+ if (rules.length === 0) {
52
+ return;
53
+ }
54
+
55
+ const networkDeviceWithDetails: NetworkDevice | null =
56
+ await NetworkDeviceService.findOneById({
57
+ id: networkDevice.id,
58
+ select: {
59
+ name: true,
60
+ description: true,
61
+ labels: { _id: true },
62
+ },
63
+ props: { isRoot: true },
64
+ });
65
+
66
+ if (!networkDeviceWithDetails) {
67
+ return;
68
+ }
69
+
70
+ const usersByNotify: Map<boolean, Set<string>> = new Map([
71
+ [true, new Set()],
72
+ [false, new Set()],
73
+ ]);
74
+ const teamsByNotify: Map<boolean, Set<string>> = new Map([
75
+ [true, new Set()],
76
+ [false, new Set()],
77
+ ]);
78
+
79
+ const matchedRules: Array<NetworkDeviceOwnerRule> = [];
80
+
81
+ for (const rule of rules) {
82
+ const matches: boolean = this.doesNetworkDeviceMatchRule(
83
+ networkDeviceWithDetails,
84
+ rule,
85
+ );
86
+ if (!matches) {
87
+ continue;
88
+ }
89
+ let ruleAddedAny: boolean = false;
90
+ const notify: boolean = rule.notifyOwners !== false;
91
+ for (const user of rule.ownerUsers || []) {
92
+ if (user.id) {
93
+ usersByNotify.get(notify)!.add(user.id.toString());
94
+ ruleAddedAny = true;
95
+ }
96
+ }
97
+ for (const team of rule.ownerTeams || []) {
98
+ if (team.id) {
99
+ teamsByNotify.get(notify)!.add(team.id.toString());
100
+ ruleAddedAny = true;
101
+ }
102
+ }
103
+ if (ruleAddedAny) {
104
+ matchedRules.push(rule);
105
+ }
106
+ }
107
+
108
+ if (matchedRules.length === 0) {
109
+ return;
110
+ }
111
+
112
+ for (const notify of [true, false]) {
113
+ const userIds: Set<string> = usersByNotify.get(notify)!;
114
+ const teamIds: Set<string> = teamsByNotify.get(notify)!;
115
+
116
+ for (const userId of userIds) {
117
+ const owner: NetworkDeviceOwnerUser = new NetworkDeviceOwnerUser();
118
+ owner.networkDeviceId = networkDevice.id;
119
+ owner.projectId = networkDevice.projectId;
120
+ owner.userId = new ObjectID(userId);
121
+ owner.isOwnerNotified = !notify;
122
+ await NetworkDeviceOwnerUserService.create({
123
+ data: owner,
124
+ props: { isRoot: true },
125
+ });
126
+ }
127
+
128
+ for (const teamId of teamIds) {
129
+ const owner: NetworkDeviceOwnerTeam = new NetworkDeviceOwnerTeam();
130
+ owner.networkDeviceId = networkDevice.id;
131
+ owner.projectId = networkDevice.projectId;
132
+ owner.teamId = new ObjectID(teamId);
133
+ owner.isOwnerNotified = !notify;
134
+ await NetworkDeviceOwnerTeamService.create({
135
+ data: owner,
136
+ props: { isRoot: true },
137
+ });
138
+ }
139
+ }
140
+
141
+ logger.debug(
142
+ `NetworkDeviceOwnerRuleEngine added owners to network device ${networkDevice.id}`,
143
+ { projectId: networkDevice.projectId.toString() } as LogAttributes,
144
+ );
145
+ } catch (error) {
146
+ logger.error(`Error applying network device owner rules: ${error}`, {
147
+ projectId: networkDevice.projectId?.toString(),
148
+ networkDeviceId: networkDevice.id?.toString(),
149
+ } as LogAttributes);
150
+ }
151
+ }
152
+
153
+ private doesNetworkDeviceMatchRule(
154
+ networkDevice: NetworkDevice,
155
+ rule: NetworkDeviceOwnerRule,
156
+ ): boolean {
157
+ if (rule.networkDeviceLabels && rule.networkDeviceLabels.length > 0) {
158
+ if (!networkDevice.labels || networkDevice.labels.length === 0) {
159
+ return false;
160
+ }
161
+ const ruleLabelIds: Array<string> = rule.networkDeviceLabels.map(
162
+ (l: Label) => {
163
+ return l.id?.toString() || "";
164
+ },
165
+ );
166
+ const labelIds: Array<string> = networkDevice.labels.map((l: Label) => {
167
+ return l.id?.toString() || "";
168
+ });
169
+ if (
170
+ !ruleLabelIds.some((id: string) => {
171
+ return labelIds.includes(id);
172
+ })
173
+ ) {
174
+ return false;
175
+ }
176
+ }
177
+
178
+ if (
179
+ rule.networkDeviceNamePattern &&
180
+ (!networkDevice.name ||
181
+ !this.testRegex(
182
+ rule.networkDeviceNamePattern,
183
+ networkDevice.name,
184
+ rule,
185
+ ))
186
+ ) {
187
+ return false;
188
+ }
189
+
190
+ if (
191
+ rule.networkDeviceDescriptionPattern &&
192
+ (!networkDevice.description ||
193
+ !this.testRegex(
194
+ rule.networkDeviceDescriptionPattern,
195
+ networkDevice.description,
196
+ rule,
197
+ ))
198
+ ) {
199
+ return false;
200
+ }
201
+
202
+ return true;
203
+ }
204
+
205
+ private testRegex(
206
+ pattern: string,
207
+ value: string,
208
+ rule: NetworkDeviceOwnerRule,
209
+ ): boolean {
210
+ try {
211
+ const regex: RegExp = new RegExp(pattern, "i");
212
+ return regex.test(value);
213
+ } catch {
214
+ logger.warn(
215
+ `Invalid regex in network device owner rule ${rule.id}: ${pattern}`,
216
+ );
217
+ return false;
218
+ }
219
+ }
220
+ }
221
+
222
+ export default new NetworkDeviceOwnerRuleEngineServiceClass();
@@ -0,0 +1,14 @@
1
+ import DatabaseService from "./DatabaseService";
2
+ import Model from "../../Models/DatabaseModels/NetworkDeviceOwnerRule";
3
+ import { IsBillingEnabled } from "../EnvironmentConfig";
4
+
5
+ export class Service extends DatabaseService<Model> {
6
+ public constructor() {
7
+ super(Model);
8
+ if (IsBillingEnabled) {
9
+ this.hardDeleteItemsOlderThanInDays("createdAt", 3 * 365);
10
+ }
11
+ }
12
+ }
13
+
14
+ export default new Service();
@@ -0,0 +1,10 @@
1
+ import DatabaseService from "./DatabaseService";
2
+ import Model from "../../Models/DatabaseModels/NetworkDeviceOwnerTeam";
3
+
4
+ export class Service extends DatabaseService<Model> {
5
+ public constructor() {
6
+ super(Model);
7
+ }
8
+ }
9
+
10
+ export default new Service();
@@ -0,0 +1,10 @@
1
+ import DatabaseService from "./DatabaseService";
2
+ import Model from "../../Models/DatabaseModels/NetworkDeviceOwnerUser";
3
+
4
+ export class Service extends DatabaseService<Model> {
5
+ public constructor() {
6
+ super(Model);
7
+ }
8
+ }
9
+
10
+ export default new Service();