@oneuptime/common 11.5.9 → 11.5.10

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 (376) hide show
  1. package/Models/AnalyticsModels/Index.ts +13 -0
  2. package/Models/AnalyticsModels/MetricItemAggMV1mByContainer.ts +178 -0
  3. package/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.ts +179 -0
  4. package/Models/AnalyticsModels/MetricItemAggMV1mByService.ts +179 -0
  5. package/Models/AnalyticsModels/NetworkFlow.ts +397 -0
  6. package/Models/DatabaseModels/EnterpriseLicenseInstance.ts +18 -0
  7. package/Models/DatabaseModels/GlobalConfig.ts +36 -0
  8. package/Models/DatabaseModels/Index.ts +2 -0
  9. package/Models/DatabaseModels/MarketingConversion.ts +198 -0
  10. package/Models/DatabaseModels/MetricSavedView.ts +34 -0
  11. package/Models/DatabaseModels/MetricType.ts +74 -0
  12. package/Models/DatabaseModels/NetworkDevice.ts +332 -0
  13. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +113 -0
  14. package/Models/DatabaseModels/NetworkInterface.ts +58 -0
  15. package/Models/DatabaseModels/Project.ts +37 -0
  16. package/Models/DatabaseModels/User.ts +37 -0
  17. package/Server/API/BaseAnalyticsAPI.ts +23 -0
  18. package/Server/API/EnterpriseLicenseAPI.ts +14 -0
  19. package/Server/EnvironmentConfig.ts +84 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.ts +38 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.ts +28 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.ts +108 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.ts +31 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.ts +29 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.ts +35 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  27. package/Server/Services/AnalyticsDatabaseService.ts +70 -1
  28. package/Server/Services/IncidentService.ts +13 -0
  29. package/Server/Services/Index.ts +10 -0
  30. package/Server/Services/MarketingConversionService.ts +10 -0
  31. package/Server/Services/MetricItemAggMV1mByContainerService.ts +31 -0
  32. package/Server/Services/MetricItemAggMV1mByK8sClusterService.ts +31 -0
  33. package/Server/Services/MetricItemAggMV1mByServiceService.ts +31 -0
  34. package/Server/Services/MetricService.ts +970 -122
  35. package/Server/Services/MonitorService.ts +14 -0
  36. package/Server/Services/NetworkDeviceOwnerTeamService.ts +42 -0
  37. package/Server/Services/NetworkDeviceOwnerUserService.ts +106 -0
  38. package/Server/Services/NetworkFlowService.ts +11 -0
  39. package/Server/Services/OnCallDutyPolicyService.ts +11 -1
  40. package/Server/Services/ProjectService.ts +136 -0
  41. package/Server/Services/SpanService.ts +13 -9
  42. package/Server/Services/StatusPageService.ts +10 -0
  43. package/Server/Services/TeamMemberService.ts +11 -0
  44. package/Server/Services/UserService.ts +59 -0
  45. package/Server/Types/AnalyticsDatabase/AggregateBy.ts +37 -7
  46. package/Server/Utils/Attribution.ts +99 -0
  47. package/Server/Utils/Marketing/ConversionUploadProvider.ts +103 -0
  48. package/Server/Utils/Marketing/ConversionUploadProviders.ts +22 -0
  49. package/Server/Utils/Marketing/Providers/GoogleAds.ts +270 -0
  50. package/Server/Utils/Marketing/Providers/LinkedIn.ts +147 -0
  51. package/Server/Utils/Marketing/Providers/Meta.ts +148 -0
  52. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +196 -0
  53. package/Server/Utils/Marketing/Providers/Reddit.ts +178 -0
  54. package/Server/Utils/Monitor/MonitorAlert.ts +71 -7
  55. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +31 -19
  56. package/Server/Utils/Monitor/MonitorIncident.ts +71 -7
  57. package/Server/Utils/Monitor/MonitorMetricUtil.ts +57 -0
  58. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +94 -0
  59. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +15 -0
  60. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +125 -14
  61. package/Server/Utils/ProductAnalytics.ts +133 -0
  62. package/Server/Utils/Telemetry/Telemetry.ts +39 -0
  63. package/Server/Utils/Telemetry/TelemetryEntity.ts +21 -0
  64. package/Tests/Server/API/BaseAnalyticsAPI.test.ts +72 -0
  65. package/Tests/Server/Infrastructure/SemaphorePermit.test.ts +9 -1
  66. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +21 -2
  67. package/Tests/Server/Services/MetricEntityMVKeyParity.test.ts +173 -0
  68. package/Tests/Server/Services/MetricServiceAggregate.test.ts +1391 -0
  69. package/Tests/Server/Services/NetworkDeviceOwnerServices.test.ts +260 -0
  70. package/Tests/Server/Utils/Monitor/MonitorTemplateUtilNetworkDevice.test.ts +389 -0
  71. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +764 -0
  72. package/Tests/Types/BaseDatabase/AggregationIntervalUtil.test.ts +111 -2
  73. package/Tests/Types/Database/EndsWith.test.ts +64 -0
  74. package/Tests/Types/Database/GreaterThan.test.ts +62 -0
  75. package/Tests/Types/Database/GreaterThanOrEqual.test.ts +65 -0
  76. package/Tests/Types/Database/GreaterThanOrNull.test.ts +63 -0
  77. package/Tests/Types/Database/Includes.test.ts +65 -0
  78. package/Tests/Types/Database/IncludesAll.test.ts +65 -0
  79. package/Tests/Types/Database/IncludesNone.test.ts +65 -0
  80. package/Tests/Types/Database/IsNull.test.ts +44 -0
  81. package/Tests/Types/Database/LessThan.test.ts +62 -0
  82. package/Tests/Types/Database/LessThanOrEqual.test.ts +62 -0
  83. package/Tests/Types/Database/LessThanOrNull.test.ts +62 -0
  84. package/Tests/Types/Database/MultiSearch.test.ts +81 -0
  85. package/Tests/Types/Database/NotContains.test.ts +64 -0
  86. package/Tests/Types/Database/NotNull.test.ts +44 -0
  87. package/Tests/Types/Database/StartsWith.test.ts +64 -0
  88. package/Tests/Types/Monitor/MonitorStepSqlMonitor.test.ts +83 -1
  89. package/Tests/Types/Monitor/SnmpV3EnumParsing.test.ts +247 -0
  90. package/Tests/Types/Monitor/SnmpVendorTemplate.test.ts +263 -0
  91. package/Tests/UI/Components/XAxis.test.ts +5 -3
  92. package/Tests/Utils/EnterpriseLicenseUsage.test.ts +76 -0
  93. package/Tests/Utils/Metrics/MetricExplorerUrl.test.ts +622 -0
  94. package/Tests/Utils/Metrics/MetricFormulaEvaluator.test.ts +474 -0
  95. package/Tests/Utils/Telemetry/HeartbeatAvailability.test.ts +52 -4
  96. package/Types/AnalyticsDatabase/AnalyticsTableName.ts +11 -0
  97. package/Types/BaseDatabase/AggregateBy.ts +31 -2
  98. package/Types/BaseDatabase/AggregatedResult.ts +22 -0
  99. package/Types/BaseDatabase/AggregationInterval.ts +11 -0
  100. package/Types/BaseDatabase/AggregationIntervalUtil.ts +30 -5
  101. package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +16 -0
  102. package/Types/Email/EmailTemplateType.ts +3 -0
  103. package/Types/Marketing/MarketingConversion.ts +11 -0
  104. package/Types/Metrics/MetricQueryConfigData.ts +21 -0
  105. package/Types/Metrics/MetricQueryData.ts +8 -0
  106. package/Types/Metrics/MetricViewData.ts +8 -0
  107. package/Types/Monitor/MonitorMetricType.ts +8 -0
  108. package/Types/Monitor/MonitorStep.ts +9 -0
  109. package/Types/Monitor/MonitorStepSqlMonitor.ts +12 -0
  110. package/Types/Monitor/MonitorType.ts +2 -1
  111. package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +17 -12
  112. package/Types/Monitor/SnmpMonitor/CdpNeighbor.ts +13 -0
  113. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +37 -3
  114. package/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.ts +46 -0
  115. package/Types/Monitor/SnmpMonitor/SnmpEntityInfo.ts +15 -0
  116. package/Types/Monitor/SnmpMonitor/SnmpInterface.ts +8 -0
  117. package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +17 -8
  118. package/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.ts +53 -0
  119. package/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.ts +43 -0
  120. package/Types/Monitor/SnmpMonitor/SnmpSystemInfo.ts +16 -0
  121. package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +119 -3
  122. package/Types/NetFlow/NetworkFlowRecord.ts +25 -0
  123. package/Types/Syslog/SyslogMessage.ts +18 -0
  124. package/Types/Telemetry/TelemetrySavedViewState.ts +9 -0
  125. package/Types/Telemetry/TelemetrySavedViewType.ts +12 -0
  126. package/UI/Components/Charts/Area/AreaChart.tsx +51 -0
  127. package/UI/Components/Charts/Bar/BarChart.tsx +51 -1
  128. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +97 -26
  129. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +328 -1
  130. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +115 -0
  131. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +328 -1
  132. package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +7 -0
  133. package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +15 -0
  134. package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +13 -0
  135. package/UI/Components/Charts/Line/LineChart.tsx +51 -0
  136. package/UI/Components/Charts/Types/ReferenceRegionProps.ts +12 -0
  137. package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +12 -0
  138. package/UI/Components/Charts/Types/XAxis/XAxisPrecision.ts +1 -0
  139. package/UI/Components/Charts/Utils/DataPoint.ts +0 -0
  140. package/UI/Components/Charts/Utils/TimeAnnotation.ts +169 -0
  141. package/UI/Components/Charts/Utils/XAxis.ts +28 -4
  142. package/UI/Components/Icon/Icon.tsx +33 -13
  143. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +9 -0
  144. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +67 -0
  145. package/UI/Components/Page/ModelPage.tsx +6 -1
  146. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +33 -4
  147. package/UI/Styles/Theme.css +10 -0
  148. package/UI/Utils/User.ts +41 -2
  149. package/Utils/Analytics.ts +8 -6
  150. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +74 -0
  151. package/Utils/Metrics/MetricExplorerUrl.ts +771 -0
  152. package/Utils/Metrics/MetricFormulaEvaluator.ts +410 -46
  153. package/Utils/Monitor/NetworkTopologyUtil.ts +261 -49
  154. package/Utils/ValueFormatter.ts +22 -1
  155. package/build/dist/Models/AnalyticsModels/Index.js +13 -0
  156. package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
  157. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js +159 -0
  158. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js.map +1 -0
  159. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js +158 -0
  160. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js.map +1 -0
  161. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js +160 -0
  162. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js.map +1 -0
  163. package/build/dist/Models/AnalyticsModels/NetworkFlow.js +351 -0
  164. package/build/dist/Models/AnalyticsModels/NetworkFlow.js.map +1 -0
  165. package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js +19 -0
  166. package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js.map +1 -1
  167. package/build/dist/Models/DatabaseModels/GlobalConfig.js +38 -0
  168. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  169. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  170. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  171. package/build/dist/Models/DatabaseModels/MarketingConversion.js +219 -0
  172. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +1 -0
  173. package/build/dist/Models/DatabaseModels/MetricSavedView.js +35 -0
  174. package/build/dist/Models/DatabaseModels/MetricSavedView.js.map +1 -1
  175. package/build/dist/Models/DatabaseModels/MetricType.js +76 -0
  176. package/build/dist/Models/DatabaseModels/MetricType.js.map +1 -1
  177. package/build/dist/Models/DatabaseModels/NetworkDevice.js +341 -0
  178. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  179. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +116 -0
  180. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  181. package/build/dist/Models/DatabaseModels/NetworkInterface.js +60 -0
  182. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
  183. package/build/dist/Models/DatabaseModels/Project.js +38 -0
  184. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  185. package/build/dist/Models/DatabaseModels/User.js +38 -0
  186. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  187. package/build/dist/Server/API/BaseAnalyticsAPI.js +19 -0
  188. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  189. package/build/dist/Server/API/EnterpriseLicenseAPI.js +8 -0
  190. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  191. package/build/dist/Server/EnvironmentConfig.js +51 -0
  192. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  193. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.js +27 -0
  194. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.js.map +1 -0
  195. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.js +21 -0
  196. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.js.map +1 -0
  197. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.js +47 -0
  198. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.js.map +1 -0
  199. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.js +16 -0
  200. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.js.map +1 -0
  201. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.js +18 -0
  202. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.js.map +1 -0
  203. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.js +20 -0
  204. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.js.map +1 -0
  205. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  206. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  207. package/build/dist/Server/Services/AnalyticsDatabaseService.js +58 -4
  208. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  209. package/build/dist/Server/Services/IncidentService.js +12 -0
  210. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  211. package/build/dist/Server/Services/Index.js +10 -0
  212. package/build/dist/Server/Services/Index.js.map +1 -1
  213. package/build/dist/Server/Services/MarketingConversionService.js +9 -0
  214. package/build/dist/Server/Services/MarketingConversionService.js.map +1 -0
  215. package/build/dist/Server/Services/MetricItemAggMV1mByContainerService.js +29 -0
  216. package/build/dist/Server/Services/MetricItemAggMV1mByContainerService.js.map +1 -0
  217. package/build/dist/Server/Services/MetricItemAggMV1mByK8sClusterService.js +29 -0
  218. package/build/dist/Server/Services/MetricItemAggMV1mByK8sClusterService.js.map +1 -0
  219. package/build/dist/Server/Services/MetricItemAggMV1mByServiceService.js +29 -0
  220. package/build/dist/Server/Services/MetricItemAggMV1mByServiceService.js.map +1 -0
  221. package/build/dist/Server/Services/MetricService.js +761 -125
  222. package/build/dist/Server/Services/MetricService.js.map +1 -1
  223. package/build/dist/Server/Services/MonitorService.js +18 -5
  224. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  225. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js +44 -0
  226. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js.map +1 -1
  227. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js +88 -0
  228. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js.map +1 -1
  229. package/build/dist/Server/Services/NetworkFlowService.js +9 -0
  230. package/build/dist/Server/Services/NetworkFlowService.js.map +1 -0
  231. package/build/dist/Server/Services/OnCallDutyPolicyService.js +15 -6
  232. package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
  233. package/build/dist/Server/Services/ProjectService.js +107 -6
  234. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  235. package/build/dist/Server/Services/SpanService.js +8 -6
  236. package/build/dist/Server/Services/SpanService.js.map +1 -1
  237. package/build/dist/Server/Services/StatusPageService.js +10 -0
  238. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  239. package/build/dist/Server/Services/TeamMemberService.js +11 -0
  240. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  241. package/build/dist/Server/Services/UserService.js +52 -0
  242. package/build/dist/Server/Services/UserService.js.map +1 -1
  243. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +33 -7
  244. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
  245. package/build/dist/Server/Utils/Attribution.js +74 -0
  246. package/build/dist/Server/Utils/Attribution.js.map +1 -0
  247. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +40 -0
  248. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +1 -0
  249. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +20 -0
  250. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +1 -0
  251. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +177 -0
  252. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +1 -0
  253. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +113 -0
  254. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +1 -0
  255. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +109 -0
  256. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +1 -0
  257. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +130 -0
  258. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +1 -0
  259. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +126 -0
  260. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +1 -0
  261. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +53 -9
  262. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  263. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +21 -10
  264. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  265. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +54 -11
  266. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  267. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +43 -3
  268. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  269. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +68 -0
  270. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  271. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +15 -0
  272. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  273. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +100 -15
  274. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  275. package/build/dist/Server/Utils/ProductAnalytics.js +111 -0
  276. package/build/dist/Server/Utils/ProductAnalytics.js.map +1 -0
  277. package/build/dist/Server/Utils/Telemetry/Telemetry.js +32 -5
  278. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  279. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -0
  280. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  281. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +11 -0
  282. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
  283. package/build/dist/Types/BaseDatabase/AggregationInterval.js +11 -0
  284. package/build/dist/Types/BaseDatabase/AggregationInterval.js.map +1 -1
  285. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +33 -5
  286. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -1
  287. package/build/dist/Types/Email/EmailTemplateType.js +2 -0
  288. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  289. package/build/dist/Types/Marketing/MarketingConversion.js +13 -0
  290. package/build/dist/Types/Marketing/MarketingConversion.js.map +1 -0
  291. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  292. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  293. package/build/dist/Types/Monitor/MonitorStep.js +6 -0
  294. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  295. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js +3 -0
  296. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
  297. package/build/dist/Types/Monitor/MonitorType.js +2 -1
  298. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  299. package/build/dist/Types/Monitor/SnmpMonitor/CdpNeighbor.js +2 -0
  300. package/build/dist/Types/Monitor/SnmpMonitor/CdpNeighbor.js.map +1 -0
  301. package/build/dist/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.js +41 -0
  302. package/build/dist/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.js.map +1 -1
  303. package/build/dist/Types/Monitor/SnmpMonitor/SnmpEntityInfo.js +2 -0
  304. package/build/dist/Types/Monitor/SnmpMonitor/SnmpEntityInfo.js.map +1 -0
  305. package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js +48 -0
  306. package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js.map +1 -1
  307. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js +38 -0
  308. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js.map +1 -1
  309. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSystemInfo.js +2 -0
  310. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSystemInfo.js.map +1 -0
  311. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +96 -3
  312. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -1
  313. package/build/dist/Types/NetFlow/NetworkFlowRecord.js +2 -0
  314. package/build/dist/Types/NetFlow/NetworkFlowRecord.js.map +1 -0
  315. package/build/dist/Types/Syslog/SyslogMessage.js +2 -0
  316. package/build/dist/Types/Syslog/SyslogMessage.js.map +1 -0
  317. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js +0 -7
  318. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js.map +1 -1
  319. package/build/dist/Types/Telemetry/TelemetrySavedViewType.js +13 -0
  320. package/build/dist/Types/Telemetry/TelemetrySavedViewType.js.map +1 -0
  321. package/build/dist/UI/Components/Charts/Area/AreaChart.js +25 -1
  322. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  323. package/build/dist/UI/Components/Charts/Bar/BarChart.js +26 -2
  324. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  325. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +36 -12
  326. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  327. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +208 -6
  328. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  329. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +52 -3
  330. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  331. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +208 -6
  332. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  333. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +6 -1
  334. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
  335. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.js +2 -0
  336. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.js.map +1 -0
  337. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.js +2 -0
  338. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.js.map +1 -0
  339. package/build/dist/UI/Components/Charts/Line/LineChart.js +25 -1
  340. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  341. package/build/dist/UI/Components/Charts/Types/ReferenceRegionProps.js +2 -0
  342. package/build/dist/UI/Components/Charts/Types/ReferenceRegionProps.js.map +1 -0
  343. package/build/dist/UI/Components/Charts/Types/TimeReferenceLineProps.js +2 -0
  344. package/build/dist/UI/Components/Charts/Types/TimeReferenceLineProps.js.map +1 -0
  345. package/build/dist/UI/Components/Charts/Types/XAxis/XAxisPrecision.js +1 -0
  346. package/build/dist/UI/Components/Charts/Types/XAxis/XAxisPrecision.js.map +1 -1
  347. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +0 -0
  348. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  349. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +121 -0
  350. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -0
  351. package/build/dist/UI/Components/Charts/Utils/XAxis.js +27 -4
  352. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  353. package/build/dist/UI/Components/Icon/Icon.js +15 -8
  354. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  355. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  356. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +58 -0
  357. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  358. package/build/dist/UI/Components/Page/ModelPage.js +7 -1
  359. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  360. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +10 -4
  361. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
  362. package/build/dist/UI/Utils/User.js +35 -2
  363. package/build/dist/UI/Utils/User.js.map +1 -1
  364. package/build/dist/Utils/Analytics.js +8 -5
  365. package/build/dist/Utils/Analytics.js.map +1 -1
  366. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +57 -0
  367. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  368. package/build/dist/Utils/Metrics/MetricExplorerUrl.js +418 -0
  369. package/build/dist/Utils/Metrics/MetricExplorerUrl.js.map +1 -0
  370. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js +296 -37
  371. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js.map +1 -1
  372. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +176 -40
  373. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  374. package/build/dist/Utils/ValueFormatter.js +20 -1
  375. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  376. package/package.json +2 -2
@@ -0,0 +1,764 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
2
+ import NetworkInventoryUtil from "../../../../Server/Utils/Monitor/NetworkInventoryUtil";
3
+ import NetworkDeviceService from "../../../../Server/Services/NetworkDeviceService";
4
+ import NetworkInterfaceService from "../../../../Server/Services/NetworkInterfaceService";
5
+ import Monitor from "../../../../Models/DatabaseModels/Monitor";
6
+ import NetworkDevice from "../../../../Models/DatabaseModels/NetworkDevice";
7
+ import NetworkInterface from "../../../../Models/DatabaseModels/NetworkInterface";
8
+ import MonitorStep from "../../../../Types/Monitor/MonitorStep";
9
+ import MonitorSteps from "../../../../Types/Monitor/MonitorSteps";
10
+ import ObjectID from "../../../../Types/ObjectID";
11
+ import OneUptimeDate from "../../../../Types/Date";
12
+ import ProbeMonitorResponse from "../../../../Types/Probe/ProbeMonitorResponse";
13
+ import SnmpInterface from "../../../../Types/Monitor/SnmpMonitor/SnmpInterface";
14
+ import SnmpMonitorResponse from "../../../../Types/Monitor/SnmpMonitor/SnmpMonitorResponse";
15
+ import LldpNeighbor from "../../../../Types/Monitor/SnmpMonitor/LldpNeighbor";
16
+ import CdpNeighbor from "../../../../Types/Monitor/SnmpMonitor/CdpNeighbor";
17
+
18
+ /*
19
+ * NetworkInventoryUtil.updateFromWalk is the single writer that keeps the
20
+ * NetworkDevice / NetworkInterface inventory in sync with each SNMP
21
+ * interface walk. These tests mock the two services it writes through and
22
+ * pin the enrichment contract: which walked fields land on the device row
23
+ * (and at what column-limit truncation), how uptime becomes lastRebootedAt,
24
+ * how the vendor is chosen, the LLDP/CDP snapshot semantics (store-even-
25
+ * when-empty, capped), and what flows into the interface upsert on both the
26
+ * update and create paths.
27
+ */
28
+
29
+ const DEVICE_ID: string = "8f2c1f0e-0000-4000-8000-0000000000aa";
30
+ const NOW: Date = new Date("2026-07-16T12:00:00.000Z");
31
+
32
+ const CISCO_SYS_OBJECT_ID: string = "1.3.6.1.4.1.9.1.1208";
33
+
34
+ type DeviceUpdatePayload = Record<string, unknown>;
35
+
36
+ let deviceFindSpy: jest.SpyInstance;
37
+ let deviceUpdateSpy: jest.SpyInstance;
38
+ let interfaceFindSpy: jest.SpyInstance;
39
+ let interfaceUpdateSpy: jest.SpyInstance;
40
+ let interfaceCreateSpy: jest.SpyInstance;
41
+
42
+ function mockServices(existingInterfaces: Array<NetworkInterface> = []): void {
43
+ /*
44
+ * The project-membership guard resolves the device (scoped to the
45
+ * monitor's project) before any write; return a matching device so the
46
+ * write path runs. The cross-project-refusal case overrides this to null.
47
+ */
48
+ const ownedDevice: NetworkDevice = new NetworkDevice();
49
+ ownedDevice.id = new ObjectID(DEVICE_ID);
50
+ deviceFindSpy = jest
51
+ .spyOn(NetworkDeviceService, "findOneBy")
52
+ .mockResolvedValue(ownedDevice);
53
+ deviceUpdateSpy = jest
54
+ .spyOn(NetworkDeviceService, "updateOneById")
55
+ .mockResolvedValue(undefined);
56
+ interfaceFindSpy = jest
57
+ .spyOn(NetworkInterfaceService, "findBy")
58
+ .mockResolvedValue(existingInterfaces);
59
+ interfaceUpdateSpy = jest
60
+ .spyOn(NetworkInterfaceService, "updateOneById")
61
+ .mockResolvedValue(undefined);
62
+ interfaceCreateSpy = jest
63
+ .spyOn(NetworkInterfaceService, "create")
64
+ .mockResolvedValue(new NetworkInterface());
65
+ }
66
+
67
+ function deviceUpdatePayload(): DeviceUpdatePayload {
68
+ expect(deviceUpdateSpy).toHaveBeenCalledTimes(1);
69
+ return deviceUpdateSpy.mock.calls[0][0].data as DeviceUpdatePayload;
70
+ }
71
+
72
+ function buildMonitor(options?: { networkDeviceId?: string | undefined }): {
73
+ monitor: Monitor;
74
+ stepId: ObjectID;
75
+ } {
76
+ const step: MonitorStep = new MonitorStep();
77
+ step.data = {
78
+ ...step.data,
79
+ networkDeviceMonitor: {
80
+ networkDeviceId:
81
+ options && "networkDeviceId" in options
82
+ ? options.networkDeviceId
83
+ : DEVICE_ID,
84
+ monitorInterfaces: true,
85
+ },
86
+ } as MonitorStep["data"];
87
+
88
+ const monitorSteps: MonitorSteps = new MonitorSteps();
89
+ monitorSteps.data = {
90
+ monitorStepsInstanceArray: [step],
91
+ defaultMonitorStatusId: undefined,
92
+ };
93
+
94
+ const monitor: Monitor = new Monitor();
95
+ monitor.projectId = ObjectID.generate();
96
+ monitor.monitorSteps = monitorSteps;
97
+
98
+ return { monitor: monitor, stepId: step.id };
99
+ }
100
+
101
+ function buildResponse(
102
+ stepId: ObjectID,
103
+ snmpFields?: Partial<SnmpMonitorResponse>,
104
+ ): ProbeMonitorResponse {
105
+ const snmpResponse: SnmpMonitorResponse = {
106
+ isOnline: true,
107
+ responseTimeInMs: 12,
108
+ failureCause: "",
109
+ oidResponses: [],
110
+ ...snmpFields,
111
+ };
112
+
113
+ return {
114
+ projectId: ObjectID.generate(),
115
+ monitorStepId: stepId,
116
+ monitorId: ObjectID.generate(),
117
+ probeId: ObjectID.generate(),
118
+ failureCause: "",
119
+ monitoredAt: NOW,
120
+ snmpResponse: snmpResponse,
121
+ } as ProbeMonitorResponse;
122
+ }
123
+
124
+ function walkedInterface(overrides?: Partial<SnmpInterface>): SnmpInterface {
125
+ return {
126
+ interfaceIndex: 1,
127
+ name: "GigabitEthernet0/1",
128
+ isOperationallyUp: true,
129
+ isAdministrativelyUp: true,
130
+ ...overrides,
131
+ };
132
+ }
133
+
134
+ function existingInterface(interfaceIndex: number): NetworkInterface {
135
+ const row: NetworkInterface = new NetworkInterface();
136
+ row._id = "9a1b2c3d-0000-4000-8000-0000000000bb";
137
+ row.interfaceIndex = interfaceIndex;
138
+ row.isMonitored = true;
139
+ return row;
140
+ }
141
+
142
+ async function runWalk(
143
+ snmpFields?: Partial<SnmpMonitorResponse>,
144
+ ): Promise<ProbeMonitorResponse> {
145
+ const { monitor, stepId } = buildMonitor();
146
+ const response: ProbeMonitorResponse = buildResponse(stepId, snmpFields);
147
+
148
+ await NetworkInventoryUtil.updateFromWalk({
149
+ monitor: monitor,
150
+ dataToProcess: response,
151
+ });
152
+
153
+ return response;
154
+ }
155
+
156
+ beforeEach(() => {
157
+ jest.spyOn(OneUptimeDate, "getCurrentDate").mockReturnValue(NOW);
158
+ });
159
+
160
+ afterEach(() => {
161
+ jest.restoreAllMocks();
162
+ });
163
+
164
+ describe("NetworkInventoryUtil.updateFromWalk — system group enrichment", () => {
165
+ test("system fields are persisted with their column-limit truncation", async () => {
166
+ mockServices();
167
+
168
+ const longDescr: string = "d".repeat(600);
169
+ const longField: string = "x".repeat(150);
170
+
171
+ await runWalk({
172
+ systemInfo: {
173
+ sysDescr: longDescr,
174
+ sysName: longField,
175
+ sysObjectId: longField,
176
+ sysLocation: longField,
177
+ sysContact: longField,
178
+ },
179
+ });
180
+
181
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
182
+
183
+ expect(update["sysDescr"]).toBe(longDescr.substring(0, 500));
184
+ expect((update["sysDescr"] as string).length).toBe(500);
185
+ for (const field of [
186
+ "sysName",
187
+ "sysObjectId",
188
+ "sysLocation",
189
+ "sysContact",
190
+ ]) {
191
+ expect(update[field]).toBe(longField.substring(0, 100));
192
+ expect((update[field] as string).length).toBe(100);
193
+ }
194
+ });
195
+
196
+ test("short system fields are persisted verbatim", async () => {
197
+ mockServices();
198
+
199
+ await runWalk({
200
+ systemInfo: {
201
+ sysDescr: "Cisco IOS Software, C2960X",
202
+ sysName: "core-sw-01",
203
+ sysObjectId: CISCO_SYS_OBJECT_ID,
204
+ sysLocation: "rack 12",
205
+ sysContact: "netops@example.com",
206
+ },
207
+ });
208
+
209
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
210
+
211
+ expect(update["sysDescr"]).toBe("Cisco IOS Software, C2960X");
212
+ expect(update["sysName"]).toBe("core-sw-01");
213
+ expect(update["sysObjectId"]).toBe(CISCO_SYS_OBJECT_ID);
214
+ expect(update["sysLocation"]).toBe("rack 12");
215
+ expect(update["sysContact"]).toBe("netops@example.com");
216
+ });
217
+
218
+ test("fields the walk did not return are left off the update entirely", async () => {
219
+ mockServices();
220
+
221
+ await runWalk({
222
+ systemInfo: {
223
+ sysName: "core-sw-01",
224
+ },
225
+ });
226
+
227
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
228
+
229
+ expect(update["sysName"]).toBe("core-sw-01");
230
+ expect(update).not.toHaveProperty("sysDescr");
231
+ expect(update).not.toHaveProperty("sysObjectId");
232
+ expect(update).not.toHaveProperty("sysLocation");
233
+ expect(update).not.toHaveProperty("sysContact");
234
+ });
235
+
236
+ test("lastSeenAt is stamped with the walk time on a reachable poll", async () => {
237
+ mockServices();
238
+
239
+ await runWalk();
240
+
241
+ expect(deviceUpdatePayload()["lastSeenAt"]).toEqual(NOW);
242
+ });
243
+ });
244
+
245
+ describe("NetworkInventoryUtil.updateFromWalk — project-membership guard", () => {
246
+ test("refuses to write when the step's device is not in the monitor's project", async () => {
247
+ mockServices();
248
+ // The scoped lookup finds no device → the id belongs to another project.
249
+ deviceFindSpy.mockResolvedValue(null);
250
+
251
+ await runWalk({
252
+ systemInfo: { sysName: "victim-device" },
253
+ interfaces: [walkedInterface()],
254
+ });
255
+
256
+ expect(deviceUpdateSpy).not.toHaveBeenCalled();
257
+ expect(interfaceCreateSpy).not.toHaveBeenCalled();
258
+ expect(interfaceUpdateSpy).not.toHaveBeenCalled();
259
+ });
260
+ });
261
+
262
+ describe("NetworkInventoryUtil.updateFromWalk — reachability gating", () => {
263
+ test("an unreachable poll with no walk data writes nothing (no phantom lastSeenAt)", async () => {
264
+ mockServices();
265
+
266
+ const { monitor, stepId } = buildMonitor();
267
+ const response: ProbeMonitorResponse = {
268
+ projectId: ObjectID.generate(),
269
+ monitorStepId: stepId,
270
+ monitorId: ObjectID.generate(),
271
+ probeId: ObjectID.generate(),
272
+ failureCause: "Device did not respond",
273
+ monitoredAt: NOW,
274
+ isOnline: false,
275
+ snmpResponse: {
276
+ isOnline: false,
277
+ responseTimeInMs: 0,
278
+ failureCause: "Device did not respond",
279
+ oidResponses: [],
280
+ },
281
+ } as ProbeMonitorResponse;
282
+
283
+ await NetworkInventoryUtil.updateFromWalk({
284
+ monitor: monitor,
285
+ dataToProcess: response,
286
+ });
287
+
288
+ // lastSeenAt drives the up/down pill; a failed poll must not bump it.
289
+ expect(deviceUpdateSpy).not.toHaveBeenCalled();
290
+ });
291
+ });
292
+
293
+ describe("NetworkInventoryUtil.updateFromWalk — lastRebootedAt", () => {
294
+ test("uptime is converted to the absolute reboot instant", async () => {
295
+ mockServices();
296
+
297
+ const uptimeSeconds: number = 3600;
298
+ await runWalk({
299
+ systemInfo: { sysUpTimeSeconds: uptimeSeconds },
300
+ });
301
+
302
+ expect(deviceUpdatePayload()["lastRebootedAt"]).toEqual(
303
+ new Date(NOW.getTime() - uptimeSeconds * 1000),
304
+ );
305
+ });
306
+
307
+ test("an uptime of zero (device just rebooted) still records the reboot", async () => {
308
+ mockServices();
309
+
310
+ await runWalk({
311
+ systemInfo: { sysUpTimeSeconds: 0 },
312
+ });
313
+
314
+ expect(deviceUpdatePayload()["lastRebootedAt"]).toEqual(NOW);
315
+ });
316
+
317
+ test("no uptime in the walk leaves lastRebootedAt untouched", async () => {
318
+ mockServices();
319
+
320
+ await runWalk({
321
+ systemInfo: { sysName: "core-sw-01" },
322
+ });
323
+
324
+ expect(deviceUpdatePayload()).not.toHaveProperty("lastRebootedAt");
325
+ });
326
+ });
327
+
328
+ describe("NetworkInventoryUtil.updateFromWalk — vendor resolution", () => {
329
+ test("ENTITY-MIB manufacturer wins over the sysObjectID fingerprint", async () => {
330
+ mockServices();
331
+
332
+ await runWalk({
333
+ systemInfo: { sysObjectId: CISCO_SYS_OBJECT_ID },
334
+ entityInfo: { manufacturer: "Custom Networks Inc" },
335
+ });
336
+
337
+ expect(deviceUpdatePayload()["vendor"]).toBe("Custom Networks Inc");
338
+ });
339
+
340
+ test("a device without ENTITY-MIB is fingerprinted from sysObjectID", async () => {
341
+ mockServices();
342
+
343
+ await runWalk({
344
+ systemInfo: { sysObjectId: CISCO_SYS_OBJECT_ID },
345
+ });
346
+
347
+ expect(deviceUpdatePayload()["vendor"]).toBe("Cisco");
348
+ });
349
+
350
+ test("no manufacturer and an unknown sysObjectID leaves the vendor absent", async () => {
351
+ mockServices();
352
+
353
+ await runWalk({
354
+ systemInfo: { sysObjectId: "1.3.6.1.2.1.1" },
355
+ });
356
+
357
+ expect(deviceUpdatePayload()).not.toHaveProperty("vendor");
358
+ });
359
+
360
+ test("an over-long manufacturer is truncated to the column limit", async () => {
361
+ mockServices();
362
+
363
+ const longVendor: string = "v".repeat(150);
364
+ await runWalk({
365
+ entityInfo: { manufacturer: longVendor },
366
+ });
367
+
368
+ expect(deviceUpdatePayload()["vendor"]).toBe(longVendor.substring(0, 100));
369
+ });
370
+ });
371
+
372
+ describe("NetworkInventoryUtil.updateFromWalk — ENTITY-MIB hardware identity", () => {
373
+ test("model, serial, firmware and software are persisted", async () => {
374
+ mockServices();
375
+
376
+ await runWalk({
377
+ entityInfo: {
378
+ model: "WS-C2960X-48TS-L",
379
+ serialNumber: "FOC1234X0YZ",
380
+ firmwareVersion: "15.2(7)E",
381
+ softwareVersion: "15.2(7)E3",
382
+ },
383
+ });
384
+
385
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
386
+
387
+ expect(update["deviceModel"]).toBe("WS-C2960X-48TS-L");
388
+ expect(update["serialNumber"]).toBe("FOC1234X0YZ");
389
+ expect(update["firmwareVersion"]).toBe("15.2(7)E");
390
+ expect(update["softwareVersion"]).toBe("15.2(7)E3");
391
+ });
392
+
393
+ test("over-long entity fields are truncated to 100 characters", async () => {
394
+ mockServices();
395
+
396
+ const long: string = "e".repeat(150);
397
+ await runWalk({
398
+ entityInfo: {
399
+ model: long,
400
+ serialNumber: long,
401
+ firmwareVersion: long,
402
+ softwareVersion: long,
403
+ },
404
+ });
405
+
406
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
407
+
408
+ for (const field of [
409
+ "deviceModel",
410
+ "serialNumber",
411
+ "firmwareVersion",
412
+ "softwareVersion",
413
+ ]) {
414
+ expect(update[field]).toBe(long.substring(0, 100));
415
+ }
416
+ });
417
+
418
+ test("absent entity fields never appear on the update", async () => {
419
+ mockServices();
420
+
421
+ await runWalk({
422
+ entityInfo: { model: "WS-C2960X-48TS-L" },
423
+ });
424
+
425
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
426
+
427
+ expect(update["deviceModel"]).toBe("WS-C2960X-48TS-L");
428
+ expect(update).not.toHaveProperty("serialNumber");
429
+ expect(update).not.toHaveProperty("firmwareVersion");
430
+ expect(update).not.toHaveProperty("softwareVersion");
431
+ });
432
+ });
433
+
434
+ describe("NetworkInventoryUtil.updateFromWalk — LLDP/CDP neighbor snapshots", () => {
435
+ function lldpNeighbor(index: number): LldpNeighbor {
436
+ return {
437
+ localInterfaceIndex: index,
438
+ remoteSysName: `neighbor-${index}`,
439
+ remotePortId: `port-${index}`,
440
+ };
441
+ }
442
+
443
+ function cdpNeighbor(index: number): CdpNeighbor {
444
+ return {
445
+ localInterfaceIndex: index,
446
+ remoteDeviceId: `cdp-neighbor-${index}`,
447
+ remotePortId: `port-${index}`,
448
+ };
449
+ }
450
+
451
+ test("both neighbor snapshots are capped at 256 entries", async () => {
452
+ mockServices();
453
+
454
+ const manyLldp: Array<LldpNeighbor> = Array.from(
455
+ { length: 300 },
456
+ (_: unknown, index: number) => {
457
+ return lldpNeighbor(index);
458
+ },
459
+ );
460
+ const manyCdp: Array<CdpNeighbor> = Array.from(
461
+ { length: 300 },
462
+ (_: unknown, index: number) => {
463
+ return cdpNeighbor(index);
464
+ },
465
+ );
466
+
467
+ await runWalk({ lldpNeighbors: manyLldp, cdpNeighbors: manyCdp });
468
+
469
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
470
+
471
+ expect(update["lldpNeighbors"]).toHaveLength(256);
472
+ expect(update["cdpNeighbors"]).toHaveLength(256);
473
+ expect((update["lldpNeighbors"] as Array<LldpNeighbor>)[0]).toEqual(
474
+ lldpNeighbor(0),
475
+ );
476
+ expect((update["cdpNeighbors"] as Array<CdpNeighbor>)[255]).toEqual(
477
+ cdpNeighbor(255),
478
+ );
479
+ });
480
+
481
+ /*
482
+ * A walk that ran and found nothing must still store the empty snapshot —
483
+ * clearing stale neighbors is what keeps the topology honest after a
484
+ * cable move.
485
+ */
486
+ test("an empty walk result clears the stored snapshot rather than skipping it", async () => {
487
+ mockServices();
488
+
489
+ await runWalk({ lldpNeighbors: [], cdpNeighbors: [] });
490
+
491
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
492
+
493
+ expect(update["lldpNeighbors"]).toEqual([]);
494
+ expect(update["cdpNeighbors"]).toEqual([]);
495
+ });
496
+
497
+ test("a walk that did not collect neighbors (older probe) leaves the snapshot alone", async () => {
498
+ mockServices();
499
+
500
+ await runWalk();
501
+
502
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
503
+
504
+ expect(update).not.toHaveProperty("lldpNeighbors");
505
+ expect(update).not.toHaveProperty("cdpNeighbors");
506
+ });
507
+
508
+ test("LLDP and CDP are stored independently of each other", async () => {
509
+ mockServices();
510
+
511
+ await runWalk({ lldpNeighbors: [lldpNeighbor(1)] });
512
+
513
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
514
+
515
+ expect(update["lldpNeighbors"]).toEqual([lldpNeighbor(1)]);
516
+ expect(update).not.toHaveProperty("cdpNeighbors");
517
+ });
518
+ });
519
+
520
+ describe("NetworkInventoryUtil.updateFromWalk — cached interface counts", () => {
521
+ test("counts follow the admin-up convention", async () => {
522
+ mockServices();
523
+
524
+ await runWalk({
525
+ interfaces: [
526
+ walkedInterface({
527
+ interfaceIndex: 1,
528
+ isAdministrativelyUp: true,
529
+ isOperationallyUp: true,
530
+ }),
531
+ walkedInterface({
532
+ interfaceIndex: 2,
533
+ isAdministrativelyUp: true,
534
+ isOperationallyUp: false,
535
+ }),
536
+ // Administratively disabled: intentionally down, never a failure.
537
+ walkedInterface({
538
+ interfaceIndex: 3,
539
+ isAdministrativelyUp: false,
540
+ isOperationallyUp: false,
541
+ }),
542
+ ],
543
+ });
544
+
545
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
546
+
547
+ expect(update["interfacesTotal"]).toBe(3);
548
+ expect(update["interfacesUp"]).toBe(1);
549
+ expect(update["interfacesDown"]).toBe(1);
550
+ });
551
+ });
552
+
553
+ describe("NetworkInventoryUtil.updateFromWalk — interface upsert", () => {
554
+ test("the update path passes macAddress and interfaceType through", async () => {
555
+ mockServices([existingInterface(1)]);
556
+
557
+ await runWalk({
558
+ interfaces: [
559
+ walkedInterface({
560
+ interfaceIndex: 1,
561
+ macAddress: "aa:bb:cc:dd:ee:ff",
562
+ interfaceType: 6,
563
+ }),
564
+ ],
565
+ });
566
+
567
+ expect(interfaceUpdateSpy).toHaveBeenCalledTimes(1);
568
+ expect(interfaceCreateSpy).not.toHaveBeenCalled();
569
+
570
+ const updateData: Record<string, unknown> =
571
+ interfaceUpdateSpy.mock.calls[0][0].data;
572
+
573
+ expect(updateData["macAddress"]).toBe("aa:bb:cc:dd:ee:ff");
574
+ expect(updateData["interfaceType"]).toBe(6);
575
+ expect(updateData["name"]).toBe("GigabitEthernet0/1");
576
+ expect(updateData["lastSeenAt"]).toEqual(NOW);
577
+ });
578
+
579
+ test("the update path clears macAddress and interfaceType when the walk stops reporting them", async () => {
580
+ mockServices([existingInterface(1)]);
581
+
582
+ await runWalk({
583
+ interfaces: [walkedInterface({ interfaceIndex: 1 })],
584
+ });
585
+
586
+ const updateData: Record<string, unknown> =
587
+ interfaceUpdateSpy.mock.calls[0][0].data;
588
+
589
+ expect(updateData["macAddress"]).toBeNull();
590
+ expect(updateData["interfaceType"]).toBeNull();
591
+ });
592
+
593
+ test("the create path passes macAddress and interfaceType through", async () => {
594
+ mockServices([]);
595
+ const { monitor, stepId } = buildMonitor();
596
+
597
+ await NetworkInventoryUtil.updateFromWalk({
598
+ monitor: monitor,
599
+ dataToProcess: buildResponse(stepId, {
600
+ interfaces: [
601
+ walkedInterface({
602
+ interfaceIndex: 7,
603
+ macAddress: "aa:bb:cc:dd:ee:ff",
604
+ interfaceType: 6,
605
+ }),
606
+ ],
607
+ }),
608
+ });
609
+
610
+ expect(interfaceCreateSpy).toHaveBeenCalledTimes(1);
611
+ expect(interfaceUpdateSpy).not.toHaveBeenCalled();
612
+
613
+ const created: NetworkInterface = interfaceCreateSpy.mock.calls[0][0].data;
614
+
615
+ expect(created.macAddress).toBe("aa:bb:cc:dd:ee:ff");
616
+ expect(created.interfaceType).toBe(6);
617
+ expect(created.interfaceIndex).toBe(7);
618
+ expect(created.name).toBe("GigabitEthernet0/1");
619
+ expect(created.isMonitored).toBe(true);
620
+ expect(created.networkDeviceId?.toString()).toBe(DEVICE_ID);
621
+ expect(created.projectId?.toString()).toBe(monitor.projectId?.toString());
622
+ });
623
+
624
+ test("the create path leaves macAddress and interfaceType unset when the walk has none", async () => {
625
+ mockServices([]);
626
+
627
+ await runWalk({
628
+ interfaces: [walkedInterface({ interfaceIndex: 7 })],
629
+ });
630
+
631
+ const created: NetworkInterface = interfaceCreateSpy.mock.calls[0][0].data;
632
+
633
+ expect(created.macAddress).toBeUndefined();
634
+ expect(created.interfaceType).toBeUndefined();
635
+ });
636
+
637
+ test("over-long mac addresses are truncated on both paths", async () => {
638
+ const longMac: string = "a".repeat(150);
639
+
640
+ mockServices([existingInterface(1)]);
641
+ await runWalk({
642
+ interfaces: [walkedInterface({ interfaceIndex: 1, macAddress: longMac })],
643
+ });
644
+
645
+ expect(interfaceUpdateSpy.mock.calls[0][0].data["macAddress"]).toBe(
646
+ longMac.substring(0, 100),
647
+ );
648
+
649
+ jest.restoreAllMocks();
650
+ jest.spyOn(OneUptimeDate, "getCurrentDate").mockReturnValue(NOW);
651
+
652
+ mockServices([]);
653
+ await runWalk({
654
+ interfaces: [walkedInterface({ interfaceIndex: 1, macAddress: longMac })],
655
+ });
656
+
657
+ const created: NetworkInterface = interfaceCreateSpy.mock.calls[0][0].data;
658
+ expect(created.macAddress).toBe(longMac.substring(0, 100));
659
+ });
660
+
661
+ /*
662
+ * A user muting an interface (isMonitored=false) keeps it in inventory but
663
+ * prunes it from the in-flight response so criteria and metrics ignore it.
664
+ */
665
+ test("an unmonitored interface is still updated in inventory but pruned from the response", async () => {
666
+ const muted: NetworkInterface = existingInterface(1);
667
+ muted.isMonitored = false;
668
+ mockServices([muted]);
669
+
670
+ const response: ProbeMonitorResponse = await runWalk({
671
+ interfaces: [
672
+ walkedInterface({ interfaceIndex: 1 }),
673
+ walkedInterface({ interfaceIndex: 2, name: "GigabitEthernet0/2" }),
674
+ ],
675
+ });
676
+
677
+ // Inventory keeps the full picture: one update (index 1), one create (index 2).
678
+ expect(interfaceUpdateSpy).toHaveBeenCalledTimes(1);
679
+ expect(interfaceCreateSpy).toHaveBeenCalledTimes(1);
680
+
681
+ // The in-flight response only keeps the monitored interface.
682
+ expect(response.snmpResponse?.interfaces).toHaveLength(1);
683
+ expect(response.snmpResponse?.interfaces?.[0]?.interfaceIndex).toBe(2);
684
+ });
685
+ });
686
+
687
+ describe("NetworkInventoryUtil.updateFromWalk — walks without interfaces", () => {
688
+ test("a zero-interface walk still enriches the device but skips the interface upsert", async () => {
689
+ mockServices();
690
+
691
+ await runWalk({
692
+ interfaces: [],
693
+ systemInfo: { sysName: "core-sw-01" },
694
+ });
695
+
696
+ const update: DeviceUpdatePayload = deviceUpdatePayload();
697
+
698
+ expect(update["sysName"]).toBe("core-sw-01");
699
+ expect(update).not.toHaveProperty("interfacesTotal");
700
+ expect(update).not.toHaveProperty("interfacesUp");
701
+ expect(update).not.toHaveProperty("interfacesDown");
702
+
703
+ expect(interfaceFindSpy).not.toHaveBeenCalled();
704
+ expect(interfaceUpdateSpy).not.toHaveBeenCalled();
705
+ expect(interfaceCreateSpy).not.toHaveBeenCalled();
706
+ });
707
+
708
+ test("a walk with no snmpResponse at all still stamps lastSeenAt", async () => {
709
+ mockServices();
710
+ const { monitor, stepId } = buildMonitor();
711
+
712
+ const response: ProbeMonitorResponse = buildResponse(stepId);
713
+ delete (response as { snmpResponse?: unknown }).snmpResponse;
714
+
715
+ await NetworkInventoryUtil.updateFromWalk({
716
+ monitor: monitor,
717
+ dataToProcess: response,
718
+ });
719
+
720
+ expect(deviceUpdatePayload()).toEqual({ lastSeenAt: NOW });
721
+ expect(interfaceFindSpy).not.toHaveBeenCalled();
722
+ });
723
+ });
724
+
725
+ describe("NetworkInventoryUtil.updateFromWalk — guards", () => {
726
+ test("a response for a step that does not reference a device performs no writes", async () => {
727
+ mockServices();
728
+ const { monitor } = buildMonitor({ networkDeviceId: undefined });
729
+
730
+ await NetworkInventoryUtil.updateFromWalk({
731
+ monitor: monitor,
732
+ dataToProcess: buildResponse(ObjectID.generate()),
733
+ });
734
+
735
+ expect(deviceUpdateSpy).not.toHaveBeenCalled();
736
+ expect(interfaceFindSpy).not.toHaveBeenCalled();
737
+ });
738
+
739
+ test("a response whose step id matches no step performs no writes", async () => {
740
+ mockServices();
741
+ const { monitor } = buildMonitor();
742
+
743
+ await NetworkInventoryUtil.updateFromWalk({
744
+ monitor: monitor,
745
+ dataToProcess: buildResponse(ObjectID.generate()),
746
+ });
747
+
748
+ expect(deviceUpdateSpy).not.toHaveBeenCalled();
749
+ });
750
+
751
+ test("a monitor without a projectId performs no writes", async () => {
752
+ mockServices();
753
+ const { monitor, stepId } = buildMonitor();
754
+ // exactOptionalPropertyTypes forbids assigning undefined directly.
755
+ (monitor as { projectId?: ObjectID | undefined }).projectId = undefined;
756
+
757
+ await NetworkInventoryUtil.updateFromWalk({
758
+ monitor: monitor,
759
+ dataToProcess: buildResponse(stepId),
760
+ });
761
+
762
+ expect(deviceUpdateSpy).not.toHaveBeenCalled();
763
+ });
764
+ });