@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
@@ -19,10 +19,30 @@ import LlmProvider from "../../Models/DatabaseModels/LlmProvider";
19
19
  import LlmLog from "../../Models/DatabaseModels/LlmLog";
20
20
  import LlmLogStatus from "../../Types/LlmLogStatus";
21
21
  import ObjectID from "../../Types/ObjectID";
22
+ import OneUptimeDate from "../../Types/Date";
22
23
  import BadDataException from "../../Types/Exception/BadDataException";
23
24
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
24
25
  import logger, { LogAttributes } from "../Utils/Logger";
25
26
 
27
+ /*
28
+ * Features that run WITHOUT a human in the loop. The per-project daily token
29
+ * budget (Project.aiDailyAutonomousTokenLimit, G4) applies only to these —
30
+ * interactive chat and explicitly user-triggered AI are never budget-blocked.
31
+ * Auto-postmortem is deliberately excluded for now: it is one call per
32
+ * resolved incident, not storm-shaped; include it when it moves to the queue.
33
+ */
34
+ export const AUTONOMOUS_AI_FEATURES: Array<string> = [
35
+ "Sentinel Incident Investigation",
36
+ "Sentinel Alert Investigation",
37
+ ];
38
+
39
+ export interface AutonomousBudgetStatus {
40
+ exhausted: boolean;
41
+ // null when the project has no limit configured.
42
+ limitInTokens: number | null;
43
+ usedTokensToday: number;
44
+ }
45
+
26
46
  export interface AILogRequest {
27
47
  projectId: ObjectID;
28
48
  userId?: ObjectID | undefined;
@@ -59,6 +79,54 @@ export class Service extends BaseService {
59
79
  super();
60
80
  }
61
81
 
82
+ /*
83
+ * G4 daily budget: has this project consumed its daily autonomous-token
84
+ * allowance (UTC day)? Counts only AUTONOMOUS_AI_FEATURES tokens, so chat
85
+ * usage neither eats the autonomous budget nor is blocked by it.
86
+ */
87
+ @CaptureSpan()
88
+ public async getAutonomousDailyBudgetStatus(
89
+ projectId: ObjectID,
90
+ ): Promise<AutonomousBudgetStatus> {
91
+ const project: Project | null = await ProjectService.findOneById({
92
+ id: projectId,
93
+ select: { aiDailyAutonomousTokenLimit: true },
94
+ props: { isRoot: true },
95
+ });
96
+
97
+ const limitInTokens: number | null =
98
+ project?.aiDailyAutonomousTokenLimit ?? null;
99
+
100
+ if (limitInTokens === null) {
101
+ return { exhausted: false, limitInTokens: null, usedTokensToday: 0 };
102
+ }
103
+
104
+ /*
105
+ * A limit of 0 (or negative) pauses autonomous runs entirely — the safe
106
+ * reading of "0 tokens allowed", and doubles as a spend kill-switch.
107
+ */
108
+ if (limitInTokens <= 0) {
109
+ return { exhausted: true, limitInTokens, usedTokensToday: 0 };
110
+ }
111
+
112
+ const usedTokensToday: number = await LlmLogService.getTotalTokensUsedSince(
113
+ {
114
+ projectId,
115
+ since: OneUptimeDate.getStartOfDay(
116
+ OneUptimeDate.getCurrentDate(),
117
+ "UTC",
118
+ ),
119
+ features: AUTONOMOUS_AI_FEATURES,
120
+ },
121
+ );
122
+
123
+ return {
124
+ exhausted: usedTokensToday >= limitInTokens,
125
+ limitInTokens,
126
+ usedTokensToday,
127
+ };
128
+ }
129
+
62
130
  @CaptureSpan()
63
131
  public async executeWithLogging(
64
132
  request: AILogRequest,
@@ -169,6 +237,34 @@ export class Service extends BaseService {
169
237
  }
170
238
  }
171
239
 
240
+ /*
241
+ * G4 daily budget enforcement — autonomous features only, mirroring the
242
+ * InsufficientBalance path above. Autonomous runs fail closed on budget
243
+ * (G9); interactive features are never blocked here. A run that crosses
244
+ * the limit mid-flight errors on its next LLM call, which marks the AIRun
245
+ * Error with this message — visible in the investigation panel.
246
+ */
247
+ if (AUTONOMOUS_AI_FEATURES.includes(request.feature)) {
248
+ const budget: AutonomousBudgetStatus =
249
+ await this.getAutonomousDailyBudgetStatus(request.projectId);
250
+
251
+ if (budget.exhausted) {
252
+ const budgetMessage: string = `Daily autonomous AI token budget exhausted (${budget.usedTokensToday.toLocaleString()} of ${budget.limitInTokens?.toLocaleString()} tokens used today). Autonomous investigations resume tomorrow (UTC) — raise or unset the limit in the AI settings pages.`;
253
+
254
+ logEntry.status = LlmLogStatus.BudgetExceeded;
255
+ logEntry.statusMessage = budgetMessage.substring(0, 490);
256
+ logEntry.requestCompletedAt = new Date();
257
+ logEntry.durationMs = new Date().getTime() - startTime.getTime();
258
+
259
+ await LlmLogService.create({
260
+ data: logEntry,
261
+ props: { isRoot: true },
262
+ });
263
+
264
+ throw new BadDataException(budgetMessage);
265
+ }
266
+ }
267
+
172
268
  try {
173
269
  // Build LLM config
174
270
  const llmConfig: LLMProviderConfig = {
@@ -194,6 +290,9 @@ export class Service extends BaseService {
194
290
  temperature: request.temperature ?? 0.7,
195
291
  maxTokens: request.maxTokens,
196
292
  tools: request.tools,
293
+ ...(llmProvider.additionalParams
294
+ ? { additionalParams: llmProvider.additionalParams }
295
+ : {}),
197
296
  });
198
297
 
199
298
  const endTime: Date = new Date();
@@ -201,6 +300,8 @@ export class Service extends BaseService {
201
300
  // Update log with success info
202
301
  logEntry.status = LlmLogStatus.Success;
203
302
  logEntry.totalTokens = response.usage?.totalTokens || 0;
303
+ logEntry.cachedInputTokens = response.usage?.cachedInputTokens || 0;
304
+ logEntry.cacheCreationTokens = response.usage?.cacheCreationTokens || 0;
204
305
  logEntry.responsePreview = storeContentPreviews
205
306
  ? response.content.substring(0, 2000) // Store first 2000 chars
206
307
  : "[Redacted — this content is private to the requesting user]";
@@ -83,12 +83,7 @@ import Dictionary from "../../Types/Dictionary";
83
83
  import ProjectService from "./ProjectService";
84
84
  import IncidentTemplateService from "./IncidentTemplateService";
85
85
  import IncidentTemplate from "../../Models/DatabaseModels/IncidentTemplate";
86
- import LLMService, {
87
- LLMProviderConfig,
88
- LLMCompletionResponse,
89
- } from "../Utils/LLM/LLMService";
90
- import LlmProviderService from "./LlmProviderService";
91
- import LlmProvider from "../../Models/DatabaseModels/LlmProvider";
86
+ import AIService, { AILogResponse } from "./AIService";
92
87
  import SentinelIncidentInvestigationRunner from "../Utils/AI/Sentinel/IncidentInvestigationRunner";
93
88
  import IncidentAIContextBuilder, {
94
89
  AIGenerationContext,
@@ -3453,22 +3448,6 @@ ${incidentSeverity.name}
3453
3448
  throw new BadDataException("Incident not found");
3454
3449
  }
3455
3450
 
3456
- // Get LLM provider for the project
3457
- const llmProvider: LlmProvider | null =
3458
- await LlmProviderService.getLLMProviderForProject(incident.projectId);
3459
-
3460
- if (!llmProvider) {
3461
- throw new BadDataException(
3462
- "No LLM provider configured for this project. Please configure an LLM provider in Settings > AI > LLM Providers.",
3463
- );
3464
- }
3465
-
3466
- if (!llmProvider.llmType) {
3467
- throw new BadDataException(
3468
- "LLM provider type is not configured properly.",
3469
- );
3470
- }
3471
-
3472
3451
  // Build incident context - always include workspace messages
3473
3452
  const contextData: IncidentContextData =
3474
3453
  await IncidentAIContextBuilder.buildIncidentContext({
@@ -3484,27 +3463,21 @@ ${incidentSeverity.name}
3484
3463
  data.template,
3485
3464
  );
3486
3465
 
3487
- // Generate postmortem using LLM
3488
- const llmConfig: LLMProviderConfig = {
3489
- llmType: llmProvider.llmType,
3490
- };
3491
-
3492
- if (llmProvider.apiKey) {
3493
- llmConfig.apiKey = llmProvider.apiKey;
3494
- }
3495
-
3496
- if (llmProvider.baseUrl) {
3497
- llmConfig.baseUrl = llmProvider.baseUrl.toString();
3498
- }
3499
-
3500
- if (llmProvider.modelName) {
3501
- llmConfig.modelName = llmProvider.modelName;
3502
- }
3503
-
3504
- const response: LLMCompletionResponse = await LLMService.getCompletion({
3505
- llmProviderConfig: llmConfig,
3466
+ /*
3467
+ * Route through AIService so the call is metered, billed and budget-
3468
+ * checked like every other AI feature — the previous direct
3469
+ * LLMService.getCompletion bypassed LlmLog and cloud billing entirely.
3470
+ * Previews stay off: the prompt embeds incident context (including
3471
+ * private notes and workspace messages) whose read ACLs are narrower
3472
+ * than LlmLog's (G8).
3473
+ */
3474
+ const response: AILogResponse = await AIService.executeWithLogging({
3475
+ projectId: incident.projectId,
3476
+ feature: "Incident Postmortem",
3477
+ incidentId: data.incidentId,
3506
3478
  messages: aiContext.messages,
3507
3479
  temperature: 0.2,
3480
+ storeContentPreviews: false,
3508
3481
  });
3509
3482
 
3510
3483
  return response.content;
@@ -36,6 +36,13 @@ import IncidentStateTimelineService from "./IncidentStateTimelineService";
36
36
  import LabelService from "./LabelService";
37
37
  import KubernetesClusterService from "./KubernetesClusterService";
38
38
  import DockerHostService from "./DockerHostService";
39
+ import NetworkDeviceService from "./NetworkDeviceService";
40
+ import NetworkDeviceOwnerTeamService from "./NetworkDeviceOwnerTeamService";
41
+ import NetworkDeviceOwnerUserService from "./NetworkDeviceOwnerUserService";
42
+ import NetworkDeviceOwnerRuleService from "./NetworkDeviceOwnerRuleService";
43
+ import NetworkDeviceLabelRuleService from "./NetworkDeviceLabelRuleService";
44
+ import NetworkDeviceDiscoveryScanService from "./NetworkDeviceDiscoveryScanService";
45
+ import NetworkInterfaceService from "./NetworkInterfaceService";
39
46
  import PodmanHostService from "./PodmanHostService";
40
47
  import ProxmoxClusterService from "./ProxmoxClusterService";
41
48
  import DockerSwarmClusterService from "./DockerSwarmClusterService";
@@ -301,6 +308,13 @@ const services: Array<BaseService> = [
301
308
  LabelService,
302
309
  KubernetesClusterService,
303
310
  DockerHostService,
311
+ NetworkDeviceService,
312
+ NetworkDeviceOwnerTeamService,
313
+ NetworkDeviceOwnerUserService,
314
+ NetworkDeviceOwnerRuleService,
315
+ NetworkDeviceLabelRuleService,
316
+ NetworkDeviceDiscoveryScanService,
317
+ NetworkInterfaceService,
304
318
  PodmanHostService,
305
319
  ProxmoxClusterService,
306
320
  DockerSwarmClusterService,
@@ -0,0 +1,351 @@
1
+ import CreateBy from "../Types/Database/CreateBy";
2
+ import DeleteBy from "../Types/Database/DeleteBy";
3
+ import UpdateBy from "../Types/Database/UpdateBy";
4
+ import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
5
+ import DatabaseService from "./DatabaseService";
6
+ import IoTFleetService from "./IoTFleetService";
7
+ import IoTFleet from "../../Models/DatabaseModels/IoTFleet";
8
+ import GlobalCache from "../Infrastructure/GlobalCache";
9
+ import InMemoryTTLCache from "../Infrastructure/InMemoryTTLCache";
10
+ import ObjectID from "../../Types/ObjectID";
11
+ import OneUptimeDate from "../../Types/Date";
12
+ import PositiveNumber from "../../Types/PositiveNumber";
13
+ import BadDataException from "../../Types/Exception/BadDataException";
14
+ import LIMIT_MAX from "../../Types/Database/LimitMax";
15
+ import Model from "../../Models/DatabaseModels/IoTDeviceCredential";
16
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
17
+ import logger from "../Utils/Logger";
18
+
19
+ /*
20
+ * Cache TTLs mirror TelemetryIngestionKeyService: the positive TTL is
21
+ * the worst-case revocation lag on the MQTT hot path (the broker
22
+ * re-validates each publish through this cache, so disabling or
23
+ * deleting a credential cuts a connected device off within ~60s);
24
+ * the shorter negative TTL keeps invalid-credential floods off
25
+ * Postgres without pinning misses for long.
26
+ */
27
+ const POSITIVE_TTL_MS: number = 60 * 1000;
28
+ const NEGATIVE_TTL_MS: number = 10 * 1000;
29
+
30
+ // lastConnectedAt heartbeat writes are throttled through Redis.
31
+ const LAST_CONNECTED_CACHE_NAMESPACE: string =
32
+ "iot-device-credential-last-connected";
33
+ const LAST_CONNECTED_THROTTLE_SECONDS: number = 60;
34
+
35
+ /*
36
+ * Everything the MQTT broker needs to authenticate and scope a
37
+ * device-credential CONNECT: the tenant, and the (fleet, device)
38
+ * identity the client is allowed to publish under.
39
+ */
40
+ export interface IoTDeviceCredentialContext {
41
+ credentialId: string;
42
+ projectId: string;
43
+ iotFleetId: string;
44
+ fleetName: string;
45
+ externalId: string;
46
+ secretKey: string;
47
+ }
48
+
49
+ export class Service extends DatabaseService<Model> {
50
+ private contextCache: InMemoryTTLCache<IoTDeviceCredentialContext | null> =
51
+ new InMemoryTTLCache(10_000);
52
+
53
+ public constructor() {
54
+ super(Model);
55
+ }
56
+
57
+ @CaptureSpan()
58
+ protected override async onBeforeCreate(
59
+ createBy: CreateBy<Model>,
60
+ ): Promise<OnCreate<Model>> {
61
+ /*
62
+ * Always server-generate the secret. secretKey is a computed
63
+ * column (create ACL []), and computed columns are skipped rather
64
+ * than stripped by the create-permission check — so a
65
+ * client-supplied value would otherwise survive verbatim and
66
+ * defeat the unpredictability the MQTT password relies on.
67
+ */
68
+ createBy.data.secretKey = ObjectID.generate();
69
+
70
+ /*
71
+ * The tenant column (projectId) is forced to the caller's project
72
+ * by the framework, but the iotFleetId relation is not — reject a
73
+ * fleet that belongs to another project so a credential cannot be
74
+ * attached to a victim fleet (which would let it steer that
75
+ * fleet's inventory cleanup and mint a cross-tenant auth context).
76
+ */
77
+ await this.validateFleetBelongsToProject(createBy);
78
+
79
+ /*
80
+ * Byte-exact duplicate guard. The DB unique index is
81
+ * case-sensitive (device.id labels are matched byte-exact), so the
82
+ * check must be too — a case-insensitive @UniqueColumnBy would
83
+ * wrongly reject two legitimately-distinct device ids that differ
84
+ * only in case.
85
+ */
86
+ await this.validateDeviceIdIsUnique(createBy);
87
+
88
+ return { createBy, carryForward: null };
89
+ }
90
+
91
+ @CaptureSpan()
92
+ private async validateFleetBelongsToProject(
93
+ createBy: CreateBy<Model>,
94
+ ): Promise<void> {
95
+ if (!createBy.data.iotFleetId || !createBy.data.projectId) {
96
+ return;
97
+ }
98
+
99
+ const fleet: IoTFleet | null = await IoTFleetService.findOneById({
100
+ id: createBy.data.iotFleetId,
101
+ select: {
102
+ _id: true,
103
+ projectId: true,
104
+ },
105
+ props: { isRoot: true },
106
+ });
107
+
108
+ if (
109
+ !fleet?.projectId ||
110
+ fleet.projectId.toString() !== createBy.data.projectId.toString()
111
+ ) {
112
+ throw new BadDataException("IoT Fleet not found in this project.");
113
+ }
114
+ }
115
+
116
+ @CaptureSpan()
117
+ private async validateDeviceIdIsUnique(
118
+ createBy: CreateBy<Model>,
119
+ ): Promise<void> {
120
+ if (
121
+ !createBy.data.projectId ||
122
+ !createBy.data.iotFleetId ||
123
+ !createBy.data.externalId
124
+ ) {
125
+ return;
126
+ }
127
+
128
+ const existingCount: PositiveNumber = await this.countBy({
129
+ query: {
130
+ projectId: createBy.data.projectId,
131
+ iotFleetId: createBy.data.iotFleetId,
132
+ externalId: createBy.data.externalId,
133
+ },
134
+ props: { isRoot: true },
135
+ });
136
+
137
+ if (existingCount.toNumber() > 0) {
138
+ throw new BadDataException(
139
+ "A device with this Device ID is already registered in this fleet.",
140
+ );
141
+ }
142
+ }
143
+
144
+ @CaptureSpan()
145
+ protected override async onBeforeDelete(
146
+ deleteBy: DeleteBy<Model>,
147
+ ): Promise<OnDelete<Model>> {
148
+ /*
149
+ * We don't know which credential(s) are being deleted without an
150
+ * extra query; clear the whole cache so revocation-by-delete takes
151
+ * effect on the broker within one cache miss.
152
+ */
153
+ this.contextCache.clear();
154
+ return { deleteBy, carryForward: null };
155
+ }
156
+
157
+ @CaptureSpan()
158
+ protected override async onBeforeUpdate(
159
+ updateBy: UpdateBy<Model>,
160
+ ): Promise<OnUpdate<Model>> {
161
+ // isEnabled flips must reach the broker — same reasoning as delete.
162
+ this.contextCache.clear();
163
+ return { updateBy, carryForward: null };
164
+ }
165
+
166
+ @CaptureSpan()
167
+ protected override async onUpdateSuccess(
168
+ onUpdate: OnUpdate<Model>,
169
+ _updatedItemIds: Array<ObjectID>,
170
+ ): Promise<OnUpdate<Model>> {
171
+ /*
172
+ * Clear again AFTER the write commits: the before-hook clear races
173
+ * a concurrent getCredentialContext that could re-cache the stale
174
+ * (pre-revocation) row before the UPDATE lands. A second clear on
175
+ * success closes that window.
176
+ */
177
+ this.contextCache.clear();
178
+ return onUpdate;
179
+ }
180
+
181
+ @CaptureSpan()
182
+ protected override async onDeleteSuccess(
183
+ onDelete: OnDelete<Model>,
184
+ _itemIdsBeforeDelete: Array<ObjectID>,
185
+ ): Promise<OnDelete<Model>> {
186
+ this.contextCache.clear();
187
+ return onDelete;
188
+ }
189
+
190
+ /**
191
+ * Resolve a credential id to its auth context, with a short-lived
192
+ * in-process cache to keep the MQTT CONNECT/publish hot path off
193
+ * Postgres. Returns null for unknown, disabled, or deleted
194
+ * credentials (also cached, for a shorter TTL). The caller must
195
+ * still compare the presented secret against context.secretKey.
196
+ */
197
+ @CaptureSpan()
198
+ public async getCredentialContext(
199
+ credentialId: string,
200
+ ): Promise<IoTDeviceCredentialContext | null> {
201
+ const cached: IoTDeviceCredentialContext | null | undefined =
202
+ this.contextCache.get(credentialId);
203
+ if (cached !== undefined) {
204
+ return cached;
205
+ }
206
+
207
+ let idObject: ObjectID;
208
+ try {
209
+ idObject = new ObjectID(credentialId);
210
+ } catch {
211
+ this.contextCache.set(credentialId, null, NEGATIVE_TTL_MS);
212
+ return null;
213
+ }
214
+
215
+ const credential: Model | null = await this.findOneBy({
216
+ query: { _id: idObject },
217
+ select: {
218
+ projectId: true,
219
+ iotFleetId: true,
220
+ externalId: true,
221
+ secretKey: true,
222
+ isEnabled: true,
223
+ iotFleet: {
224
+ name: true,
225
+ },
226
+ },
227
+ props: { isRoot: true },
228
+ });
229
+
230
+ if (
231
+ !credential ||
232
+ credential.isEnabled === false ||
233
+ !credential.projectId ||
234
+ !credential.iotFleetId ||
235
+ !credential.externalId ||
236
+ !credential.secretKey ||
237
+ !credential.iotFleet?.name
238
+ ) {
239
+ this.contextCache.set(credentialId, null, NEGATIVE_TTL_MS);
240
+ return null;
241
+ }
242
+
243
+ const context: IoTDeviceCredentialContext = {
244
+ credentialId: credentialId,
245
+ projectId: credential.projectId.toString(),
246
+ iotFleetId: credential.iotFleetId.toString(),
247
+ fleetName: credential.iotFleet.name,
248
+ externalId: credential.externalId,
249
+ secretKey: credential.secretKey.toString(),
250
+ };
251
+
252
+ this.contextCache.set(credentialId, context, POSITIVE_TTL_MS);
253
+ return context;
254
+ }
255
+
256
+ /**
257
+ * Stamp lastConnectedAt for a credential, throttled to one write
258
+ * per minute per credential (heartbeat write — same hot-row
259
+ * pattern as IoTFleetService.updateLastSeen).
260
+ */
261
+ @CaptureSpan()
262
+ public async markConnected(credentialId: ObjectID): Promise<void> {
263
+ const cacheKey: string = credentialId.toString();
264
+
265
+ let cached: string | null = null;
266
+ try {
267
+ cached = await GlobalCache.getString(
268
+ LAST_CONNECTED_CACHE_NAMESPACE,
269
+ cacheKey,
270
+ );
271
+ } catch {
272
+ /*
273
+ * Fail open: a Redis blip must never skip the DB write —
274
+ * lastConnectedAt drives the registry UI's liveness column.
275
+ */
276
+ cached = null;
277
+ }
278
+
279
+ if (cached === "1") {
280
+ return;
281
+ }
282
+
283
+ try {
284
+ await GlobalCache.setString(
285
+ LAST_CONNECTED_CACHE_NAMESPACE,
286
+ cacheKey,
287
+ "1",
288
+ {
289
+ expiresInSeconds: LAST_CONNECTED_THROTTLE_SECONDS,
290
+ },
291
+ );
292
+ } catch (err) {
293
+ logger.debug(
294
+ `IoTDeviceCredential markConnected cache write failed: ${err}`,
295
+ );
296
+ }
297
+
298
+ /*
299
+ * Single no-hooks, no-version-bump UPDATE — a heartbeat write must
300
+ * not contend on hooks or lock convoys at connect storms.
301
+ */
302
+ await this.updateColumnsByIdWithoutHooks({
303
+ id: credentialId,
304
+ data: {
305
+ lastConnectedAt: OneUptimeDate.getCurrentDate(),
306
+ },
307
+ });
308
+ }
309
+
310
+ /**
311
+ * The expected-device set for a fleet — ENABLED registered device
312
+ * ids, VERBATIM (device.id labels are matched byte-exact; do not
313
+ * canonicalize). Feeds ONLY the absent-series injection in IoT
314
+ * Device monitor evaluation.
315
+ *
316
+ * Note: stale-cleanup preservation (IoTDeviceService.deleteStaleForFleet)
317
+ * deliberately does NOT use this method — it preserves any
318
+ * non-deleted credential row regardless of isEnabled, so a revoked
319
+ * (disabled) device stays in the inventory as Offline until its
320
+ * credential row is deleted, while its silent-death alerting pauses.
321
+ */
322
+ @CaptureSpan()
323
+ public async getExpectedDeviceExternalIds(data: {
324
+ projectId: ObjectID;
325
+ iotFleetId: ObjectID;
326
+ }): Promise<Array<string>> {
327
+ const credentials: Array<Model> = await this.findBy({
328
+ query: {
329
+ projectId: data.projectId,
330
+ iotFleetId: data.iotFleetId,
331
+ isEnabled: true,
332
+ },
333
+ select: {
334
+ externalId: true,
335
+ },
336
+ limit: LIMIT_MAX,
337
+ skip: 0,
338
+ props: { isRoot: true },
339
+ });
340
+
341
+ const externalIds: Array<string> = [];
342
+ for (const credential of credentials) {
343
+ if (credential.externalId) {
344
+ externalIds.push(credential.externalId);
345
+ }
346
+ }
347
+ return externalIds;
348
+ }
349
+ }
350
+
351
+ export default new Service();