@oneuptime/common 11.5.9 → 11.5.11

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 (379) 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/1784401962564-MigrationName.ts +101 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  28. package/Server/Services/AnalyticsDatabaseService.ts +70 -1
  29. package/Server/Services/IncidentService.ts +13 -0
  30. package/Server/Services/Index.ts +10 -0
  31. package/Server/Services/MarketingConversionService.ts +10 -0
  32. package/Server/Services/MetricItemAggMV1mByContainerService.ts +31 -0
  33. package/Server/Services/MetricItemAggMV1mByK8sClusterService.ts +31 -0
  34. package/Server/Services/MetricItemAggMV1mByServiceService.ts +31 -0
  35. package/Server/Services/MetricService.ts +970 -122
  36. package/Server/Services/MonitorService.ts +14 -0
  37. package/Server/Services/NetworkDeviceOwnerTeamService.ts +42 -0
  38. package/Server/Services/NetworkDeviceOwnerUserService.ts +106 -0
  39. package/Server/Services/NetworkFlowService.ts +11 -0
  40. package/Server/Services/OnCallDutyPolicyService.ts +11 -1
  41. package/Server/Services/ProjectService.ts +136 -0
  42. package/Server/Services/SpanService.ts +13 -9
  43. package/Server/Services/StatusPageService.ts +10 -0
  44. package/Server/Services/TeamMemberService.ts +11 -0
  45. package/Server/Services/UserService.ts +59 -0
  46. package/Server/Types/AnalyticsDatabase/AggregateBy.ts +37 -7
  47. package/Server/Utils/Attribution.ts +99 -0
  48. package/Server/Utils/Marketing/ConversionUploadProvider.ts +103 -0
  49. package/Server/Utils/Marketing/ConversionUploadProviders.ts +22 -0
  50. package/Server/Utils/Marketing/Providers/GoogleAds.ts +270 -0
  51. package/Server/Utils/Marketing/Providers/LinkedIn.ts +147 -0
  52. package/Server/Utils/Marketing/Providers/Meta.ts +148 -0
  53. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +196 -0
  54. package/Server/Utils/Marketing/Providers/Reddit.ts +178 -0
  55. package/Server/Utils/Monitor/MonitorAlert.ts +71 -7
  56. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +31 -19
  57. package/Server/Utils/Monitor/MonitorIncident.ts +71 -7
  58. package/Server/Utils/Monitor/MonitorMetricUtil.ts +57 -0
  59. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +94 -0
  60. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +15 -0
  61. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +125 -14
  62. package/Server/Utils/ProductAnalytics.ts +133 -0
  63. package/Server/Utils/Telemetry/Telemetry.ts +39 -0
  64. package/Server/Utils/Telemetry/TelemetryEntity.ts +21 -0
  65. package/Tests/Server/API/BaseAnalyticsAPI.test.ts +72 -0
  66. package/Tests/Server/Infrastructure/SemaphorePermit.test.ts +9 -1
  67. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +21 -2
  68. package/Tests/Server/Services/MetricEntityMVKeyParity.test.ts +173 -0
  69. package/Tests/Server/Services/MetricServiceAggregate.test.ts +1391 -0
  70. package/Tests/Server/Services/NetworkDeviceOwnerServices.test.ts +260 -0
  71. package/Tests/Server/Utils/Monitor/MonitorTemplateUtilNetworkDevice.test.ts +389 -0
  72. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +764 -0
  73. package/Tests/Types/BaseDatabase/AggregationIntervalUtil.test.ts +111 -2
  74. package/Tests/Types/Database/EndsWith.test.ts +64 -0
  75. package/Tests/Types/Database/GreaterThan.test.ts +62 -0
  76. package/Tests/Types/Database/GreaterThanOrEqual.test.ts +65 -0
  77. package/Tests/Types/Database/GreaterThanOrNull.test.ts +63 -0
  78. package/Tests/Types/Database/Includes.test.ts +65 -0
  79. package/Tests/Types/Database/IncludesAll.test.ts +65 -0
  80. package/Tests/Types/Database/IncludesNone.test.ts +65 -0
  81. package/Tests/Types/Database/IsNull.test.ts +44 -0
  82. package/Tests/Types/Database/LessThan.test.ts +62 -0
  83. package/Tests/Types/Database/LessThanOrEqual.test.ts +62 -0
  84. package/Tests/Types/Database/LessThanOrNull.test.ts +62 -0
  85. package/Tests/Types/Database/MultiSearch.test.ts +81 -0
  86. package/Tests/Types/Database/NotContains.test.ts +64 -0
  87. package/Tests/Types/Database/NotNull.test.ts +44 -0
  88. package/Tests/Types/Database/StartsWith.test.ts +64 -0
  89. package/Tests/Types/Monitor/MonitorStepSqlMonitor.test.ts +83 -1
  90. package/Tests/Types/Monitor/SnmpV3EnumParsing.test.ts +247 -0
  91. package/Tests/Types/Monitor/SnmpVendorTemplate.test.ts +263 -0
  92. package/Tests/UI/Components/XAxis.test.ts +5 -3
  93. package/Tests/Utils/EnterpriseLicenseUsage.test.ts +76 -0
  94. package/Tests/Utils/Metrics/MetricExplorerUrl.test.ts +622 -0
  95. package/Tests/Utils/Metrics/MetricFormulaEvaluator.test.ts +474 -0
  96. package/Tests/Utils/Telemetry/HeartbeatAvailability.test.ts +52 -4
  97. package/Types/AnalyticsDatabase/AnalyticsTableName.ts +11 -0
  98. package/Types/BaseDatabase/AggregateBy.ts +31 -2
  99. package/Types/BaseDatabase/AggregatedResult.ts +22 -0
  100. package/Types/BaseDatabase/AggregationInterval.ts +11 -0
  101. package/Types/BaseDatabase/AggregationIntervalUtil.ts +30 -5
  102. package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +16 -0
  103. package/Types/Email/EmailTemplateType.ts +3 -0
  104. package/Types/Marketing/MarketingConversion.ts +11 -0
  105. package/Types/Metrics/MetricQueryConfigData.ts +21 -0
  106. package/Types/Metrics/MetricQueryData.ts +8 -0
  107. package/Types/Metrics/MetricViewData.ts +8 -0
  108. package/Types/Monitor/MonitorMetricType.ts +8 -0
  109. package/Types/Monitor/MonitorStep.ts +9 -0
  110. package/Types/Monitor/MonitorStepSqlMonitor.ts +12 -0
  111. package/Types/Monitor/MonitorType.ts +2 -1
  112. package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +17 -12
  113. package/Types/Monitor/SnmpMonitor/CdpNeighbor.ts +13 -0
  114. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +37 -3
  115. package/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.ts +46 -0
  116. package/Types/Monitor/SnmpMonitor/SnmpEntityInfo.ts +15 -0
  117. package/Types/Monitor/SnmpMonitor/SnmpInterface.ts +8 -0
  118. package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +17 -8
  119. package/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.ts +53 -0
  120. package/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.ts +43 -0
  121. package/Types/Monitor/SnmpMonitor/SnmpSystemInfo.ts +16 -0
  122. package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +119 -3
  123. package/Types/NetFlow/NetworkFlowRecord.ts +25 -0
  124. package/Types/Syslog/SyslogMessage.ts +18 -0
  125. package/Types/Telemetry/TelemetrySavedViewState.ts +9 -0
  126. package/Types/Telemetry/TelemetrySavedViewType.ts +12 -0
  127. package/UI/Components/Charts/Area/AreaChart.tsx +51 -0
  128. package/UI/Components/Charts/Bar/BarChart.tsx +51 -1
  129. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +97 -26
  130. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +328 -1
  131. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +115 -0
  132. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +328 -1
  133. package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +7 -0
  134. package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +15 -0
  135. package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +13 -0
  136. package/UI/Components/Charts/Line/LineChart.tsx +51 -0
  137. package/UI/Components/Charts/Types/ReferenceRegionProps.ts +12 -0
  138. package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +12 -0
  139. package/UI/Components/Charts/Types/XAxis/XAxisPrecision.ts +1 -0
  140. package/UI/Components/Charts/Utils/DataPoint.ts +0 -0
  141. package/UI/Components/Charts/Utils/TimeAnnotation.ts +169 -0
  142. package/UI/Components/Charts/Utils/XAxis.ts +28 -4
  143. package/UI/Components/Icon/Icon.tsx +33 -13
  144. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +9 -0
  145. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +67 -0
  146. package/UI/Components/Page/ModelPage.tsx +6 -1
  147. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +33 -4
  148. package/UI/Styles/Theme.css +10 -0
  149. package/UI/Utils/User.ts +41 -2
  150. package/Utils/Analytics.ts +8 -6
  151. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +74 -0
  152. package/Utils/Metrics/MetricExplorerUrl.ts +771 -0
  153. package/Utils/Metrics/MetricFormulaEvaluator.ts +410 -46
  154. package/Utils/Monitor/NetworkTopologyUtil.ts +261 -49
  155. package/Utils/ValueFormatter.ts +22 -1
  156. package/build/dist/Models/AnalyticsModels/Index.js +13 -0
  157. package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
  158. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js +159 -0
  159. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js.map +1 -0
  160. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js +158 -0
  161. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js.map +1 -0
  162. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js +160 -0
  163. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js.map +1 -0
  164. package/build/dist/Models/AnalyticsModels/NetworkFlow.js +351 -0
  165. package/build/dist/Models/AnalyticsModels/NetworkFlow.js.map +1 -0
  166. package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js +19 -0
  167. package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js.map +1 -1
  168. package/build/dist/Models/DatabaseModels/GlobalConfig.js +38 -0
  169. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  170. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  171. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  172. package/build/dist/Models/DatabaseModels/MarketingConversion.js +219 -0
  173. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +1 -0
  174. package/build/dist/Models/DatabaseModels/MetricSavedView.js +35 -0
  175. package/build/dist/Models/DatabaseModels/MetricSavedView.js.map +1 -1
  176. package/build/dist/Models/DatabaseModels/MetricType.js +76 -0
  177. package/build/dist/Models/DatabaseModels/MetricType.js.map +1 -1
  178. package/build/dist/Models/DatabaseModels/NetworkDevice.js +341 -0
  179. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  180. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +116 -0
  181. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  182. package/build/dist/Models/DatabaseModels/NetworkInterface.js +60 -0
  183. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
  184. package/build/dist/Models/DatabaseModels/Project.js +38 -0
  185. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/User.js +38 -0
  187. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  188. package/build/dist/Server/API/BaseAnalyticsAPI.js +19 -0
  189. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  190. package/build/dist/Server/API/EnterpriseLicenseAPI.js +8 -0
  191. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  192. package/build/dist/Server/EnvironmentConfig.js +51 -0
  193. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  194. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.js +27 -0
  195. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.js.map +1 -0
  196. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.js +21 -0
  197. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.js.map +1 -0
  198. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.js +47 -0
  199. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.js.map +1 -0
  200. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.js +16 -0
  201. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.js.map +1 -0
  202. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.js +18 -0
  203. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.js.map +1 -0
  204. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.js +20 -0
  205. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.js.map +1 -0
  206. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784401962564-MigrationName.js +40 -0
  207. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784401962564-MigrationName.js.map +1 -0
  208. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  209. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  210. package/build/dist/Server/Services/AnalyticsDatabaseService.js +58 -4
  211. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  212. package/build/dist/Server/Services/IncidentService.js +12 -0
  213. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  214. package/build/dist/Server/Services/Index.js +10 -0
  215. package/build/dist/Server/Services/Index.js.map +1 -1
  216. package/build/dist/Server/Services/MarketingConversionService.js +9 -0
  217. package/build/dist/Server/Services/MarketingConversionService.js.map +1 -0
  218. package/build/dist/Server/Services/MetricItemAggMV1mByContainerService.js +29 -0
  219. package/build/dist/Server/Services/MetricItemAggMV1mByContainerService.js.map +1 -0
  220. package/build/dist/Server/Services/MetricItemAggMV1mByK8sClusterService.js +29 -0
  221. package/build/dist/Server/Services/MetricItemAggMV1mByK8sClusterService.js.map +1 -0
  222. package/build/dist/Server/Services/MetricItemAggMV1mByServiceService.js +29 -0
  223. package/build/dist/Server/Services/MetricItemAggMV1mByServiceService.js.map +1 -0
  224. package/build/dist/Server/Services/MetricService.js +761 -125
  225. package/build/dist/Server/Services/MetricService.js.map +1 -1
  226. package/build/dist/Server/Services/MonitorService.js +18 -5
  227. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  228. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js +44 -0
  229. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js.map +1 -1
  230. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js +88 -0
  231. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js.map +1 -1
  232. package/build/dist/Server/Services/NetworkFlowService.js +9 -0
  233. package/build/dist/Server/Services/NetworkFlowService.js.map +1 -0
  234. package/build/dist/Server/Services/OnCallDutyPolicyService.js +15 -6
  235. package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
  236. package/build/dist/Server/Services/ProjectService.js +107 -6
  237. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  238. package/build/dist/Server/Services/SpanService.js +8 -6
  239. package/build/dist/Server/Services/SpanService.js.map +1 -1
  240. package/build/dist/Server/Services/StatusPageService.js +10 -0
  241. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  242. package/build/dist/Server/Services/TeamMemberService.js +11 -0
  243. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  244. package/build/dist/Server/Services/UserService.js +52 -0
  245. package/build/dist/Server/Services/UserService.js.map +1 -1
  246. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +33 -7
  247. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
  248. package/build/dist/Server/Utils/Attribution.js +74 -0
  249. package/build/dist/Server/Utils/Attribution.js.map +1 -0
  250. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +40 -0
  251. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +1 -0
  252. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +20 -0
  253. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +1 -0
  254. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +177 -0
  255. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +1 -0
  256. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +113 -0
  257. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +1 -0
  258. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +109 -0
  259. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +1 -0
  260. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +130 -0
  261. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +1 -0
  262. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +126 -0
  263. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +1 -0
  264. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +53 -9
  265. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  266. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +21 -10
  267. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  268. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +54 -11
  269. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  270. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +43 -3
  271. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  272. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +68 -0
  273. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  274. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +15 -0
  275. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  276. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +100 -15
  277. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  278. package/build/dist/Server/Utils/ProductAnalytics.js +111 -0
  279. package/build/dist/Server/Utils/ProductAnalytics.js.map +1 -0
  280. package/build/dist/Server/Utils/Telemetry/Telemetry.js +32 -5
  281. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  282. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -0
  283. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  284. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +11 -0
  285. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
  286. package/build/dist/Types/BaseDatabase/AggregationInterval.js +11 -0
  287. package/build/dist/Types/BaseDatabase/AggregationInterval.js.map +1 -1
  288. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +33 -5
  289. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -1
  290. package/build/dist/Types/Email/EmailTemplateType.js +2 -0
  291. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  292. package/build/dist/Types/Marketing/MarketingConversion.js +13 -0
  293. package/build/dist/Types/Marketing/MarketingConversion.js.map +1 -0
  294. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  295. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  296. package/build/dist/Types/Monitor/MonitorStep.js +6 -0
  297. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  298. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js +3 -0
  299. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
  300. package/build/dist/Types/Monitor/MonitorType.js +2 -1
  301. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  302. package/build/dist/Types/Monitor/SnmpMonitor/CdpNeighbor.js +2 -0
  303. package/build/dist/Types/Monitor/SnmpMonitor/CdpNeighbor.js.map +1 -0
  304. package/build/dist/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.js +41 -0
  305. package/build/dist/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.js.map +1 -1
  306. package/build/dist/Types/Monitor/SnmpMonitor/SnmpEntityInfo.js +2 -0
  307. package/build/dist/Types/Monitor/SnmpMonitor/SnmpEntityInfo.js.map +1 -0
  308. package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js +48 -0
  309. package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js.map +1 -1
  310. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js +38 -0
  311. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js.map +1 -1
  312. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSystemInfo.js +2 -0
  313. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSystemInfo.js.map +1 -0
  314. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +96 -3
  315. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -1
  316. package/build/dist/Types/NetFlow/NetworkFlowRecord.js +2 -0
  317. package/build/dist/Types/NetFlow/NetworkFlowRecord.js.map +1 -0
  318. package/build/dist/Types/Syslog/SyslogMessage.js +2 -0
  319. package/build/dist/Types/Syslog/SyslogMessage.js.map +1 -0
  320. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js +0 -7
  321. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js.map +1 -1
  322. package/build/dist/Types/Telemetry/TelemetrySavedViewType.js +13 -0
  323. package/build/dist/Types/Telemetry/TelemetrySavedViewType.js.map +1 -0
  324. package/build/dist/UI/Components/Charts/Area/AreaChart.js +25 -1
  325. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  326. package/build/dist/UI/Components/Charts/Bar/BarChart.js +26 -2
  327. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  328. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +36 -12
  329. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  330. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +208 -6
  331. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  332. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +52 -3
  333. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  334. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +208 -6
  335. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  336. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +6 -1
  337. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
  338. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.js +2 -0
  339. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.js.map +1 -0
  340. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.js +2 -0
  341. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.js.map +1 -0
  342. package/build/dist/UI/Components/Charts/Line/LineChart.js +25 -1
  343. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  344. package/build/dist/UI/Components/Charts/Types/ReferenceRegionProps.js +2 -0
  345. package/build/dist/UI/Components/Charts/Types/ReferenceRegionProps.js.map +1 -0
  346. package/build/dist/UI/Components/Charts/Types/TimeReferenceLineProps.js +2 -0
  347. package/build/dist/UI/Components/Charts/Types/TimeReferenceLineProps.js.map +1 -0
  348. package/build/dist/UI/Components/Charts/Types/XAxis/XAxisPrecision.js +1 -0
  349. package/build/dist/UI/Components/Charts/Types/XAxis/XAxisPrecision.js.map +1 -1
  350. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +0 -0
  351. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  352. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +121 -0
  353. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -0
  354. package/build/dist/UI/Components/Charts/Utils/XAxis.js +27 -4
  355. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  356. package/build/dist/UI/Components/Icon/Icon.js +15 -8
  357. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  358. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  359. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +58 -0
  360. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  361. package/build/dist/UI/Components/Page/ModelPage.js +7 -1
  362. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  363. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +10 -4
  364. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
  365. package/build/dist/UI/Utils/User.js +35 -2
  366. package/build/dist/UI/Utils/User.js.map +1 -1
  367. package/build/dist/Utils/Analytics.js +8 -5
  368. package/build/dist/Utils/Analytics.js.map +1 -1
  369. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +57 -0
  370. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  371. package/build/dist/Utils/Metrics/MetricExplorerUrl.js +418 -0
  372. package/build/dist/Utils/Metrics/MetricExplorerUrl.js.map +1 -0
  373. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js +296 -37
  374. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js.map +1 -1
  375. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +176 -40
  376. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  377. package/build/dist/Utils/ValueFormatter.js +20 -1
  378. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  379. package/package.json +4 -3
@@ -3,6 +3,7 @@ import AggregatedModel from "../../Types/BaseDatabase/AggregatedModel";
3
3
  import AggregatedResult from "../../Types/BaseDatabase/AggregatedResult";
4
4
  import MetricFormulaConfigData from "../../Types/Metrics/MetricFormulaConfigData";
5
5
  import MetricQueryConfigData from "../../Types/Metrics/MetricQueryConfigData";
6
+ import { JSONObject, JSONValue } from "../../Types/JSON";
6
7
 
7
8
  /**
8
9
  * Shunting-yard based evaluator for metric formulas such as
@@ -10,6 +11,17 @@ import MetricQueryConfigData from "../../Types/Metrics/MetricQueryConfigData";
10
11
  * alias (case-insensitive, with or without a leading "$"). Evaluates
11
12
  * the formula point-by-point against a time-aligned series from the
12
13
  * referenced queries/formulas.
14
+ *
15
+ * Group-aware: when a referenced query is grouped (e.g. by "host.name")
16
+ * and its result carries multiple series, the formula is evaluated once
17
+ * per group present in ALL grouped variables (Datadog-style), and the
18
+ * group's attributes are stamped onto the output rows so chart layers
19
+ * can split them back into one line per group. Ungrouped variables
20
+ * broadcast across groups; a variable whose QUERY was grouped is joined
21
+ * by group key even when it happens to return a single series (see
22
+ * isGroupedVariable). When every referenced variable has a single
23
+ * series the evaluator behaves exactly like the original timestamp-only
24
+ * join — no stamping, identical output.
13
25
  */
14
26
 
15
27
  enum TokenType {
@@ -47,11 +59,27 @@ export interface FormulaPoint {
47
59
  value: number;
48
60
  }
49
61
 
62
+ interface VariableSeriesData {
63
+ result: AggregatedResult;
64
+ groupByAttributeKeys: Array<string>;
65
+ }
66
+
67
+ interface SeriesGroupBucket {
68
+ labels: JSONObject;
69
+ samples: Array<AggregatedModel>;
70
+ }
71
+
50
72
  export default class MetricFormulaEvaluator {
51
73
  /**
52
74
  * Evaluate a formula against the provided query/formula results and
53
75
  * return a synthetic AggregatedResult whose timestamps are the union
54
- * of all referenced series.
76
+ * of all referenced series. Grouped inputs produce one output series
77
+ * per common group, with the group attributes stamped on each row.
78
+ *
79
+ * Throws for STRUCTURAL problems (invalid formula syntax/arity,
80
+ * unknown variable, grouped variables with no groups in common).
81
+ * Per-point data gaps (a timestamp missing from one variable) are
82
+ * skipped silently, as before.
55
83
  */
56
84
  public static evaluateFormula(input: {
57
85
  formula: string;
@@ -64,9 +92,10 @@ export default class MetricFormulaEvaluator {
64
92
  return { data: [] };
65
93
  }
66
94
 
95
+ // Throws a descriptive BadDataException for syntax and arity errors.
67
96
  const rpn: Array<Token> = MetricFormulaEvaluator.toRpn(trimmedFormula);
68
97
 
69
- const variableResults: Record<string, AggregatedResult> =
98
+ const variableData: Record<string, VariableSeriesData> =
70
99
  MetricFormulaEvaluator.buildVariableResultMap({
71
100
  queryConfigs: input.queryConfigs,
72
101
  formulaConfigs: input.formulaConfigs,
@@ -82,61 +111,132 @@ export default class MetricFormulaEvaluator {
82
111
  MetricFormulaEvaluator.collectVariableNames(rpn);
83
112
 
84
113
  for (const variableName of referencedVariables) {
85
- if (!variableResults[variableName]) {
114
+ if (!variableData[variableName]) {
86
115
  throw new BadDataException(
87
116
  `Formula references unknown variable "$${variableName}". Define a metric query with that alias first.`,
88
117
  );
89
118
  }
90
119
  }
91
120
 
92
- const timestampIndex: Map<
93
- string,
94
- Record<string, number>
95
- > = MetricFormulaEvaluator.buildTimestampIndex(
96
- referencedVariables,
97
- variableResults,
121
+ /*
122
+ * Bucket each variable's rows into series groups.
123
+ */
124
+ const seriesBuckets: Record<string, Map<string, SeriesGroupBucket>> = {};
125
+
126
+ for (const variableName of referencedVariables) {
127
+ seriesBuckets[variableName] = MetricFormulaEvaluator.bucketSeriesByGroup(
128
+ variableData[variableName]!,
129
+ );
130
+ }
131
+
132
+ /*
133
+ * The grouped path only ENGAGES when some variable factually carries
134
+ * two or more series. Callers like the metric-monitor worker
135
+ * pre-bucket per series fingerprint and pass one series per variable
136
+ * (with grouped query configs still attached), and those inputs must
137
+ * remain an exact — byte-identical — passthrough of the original
138
+ * single-series behavior.
139
+ */
140
+ const hasMultiSeriesVariable: boolean = referencedVariables.some(
141
+ (variableName: string) => {
142
+ return (seriesBuckets[variableName]?.size || 0) >= 2;
143
+ },
98
144
  );
99
145
 
100
- const sortedTimestamps: Array<string> = Array.from(
101
- timestampIndex.keys(),
102
- ).sort();
146
+ if (!hasMultiSeriesVariable) {
147
+ // Single-series inputs: exact passthrough of the original behavior.
148
+ const seriesByVariable: Record<string, Array<AggregatedModel>> = {};
149
+ for (const variableName of referencedVariables) {
150
+ seriesByVariable[variableName] =
151
+ variableData[variableName]!.result.data;
152
+ }
103
153
 
104
- const resultData: Array<AggregatedModel> = [];
154
+ return {
155
+ data: MetricFormulaEvaluator.evaluatePointwise({
156
+ rpn,
157
+ referencedVariables,
158
+ seriesByVariable,
159
+ }),
160
+ };
161
+ }
105
162
 
106
- for (const timestampString of sortedTimestamps) {
107
- const values: Record<string, number> =
108
- timestampIndex.get(timestampString) || {};
163
+ /*
164
+ * Once in the grouped path, classification switches from observed
165
+ * series count to query intent where available: a variable whose
166
+ * query was grouped joins by group key even when it returned a
167
+ * single series. Every multi-series variable satisfies the
168
+ * predicate too, so groupedVariables is never empty here.
169
+ */
170
+ const groupedVariables: Array<string> = referencedVariables.filter(
171
+ (variableName: string) => {
172
+ return MetricFormulaEvaluator.isGroupedVariable(
173
+ seriesBuckets[variableName],
174
+ variableData[variableName]!,
175
+ );
176
+ },
177
+ );
109
178
 
110
- /*
111
- * Skip points where any referenced variable is missing a value. A
112
- * partial join would produce misleading numbers (e.g. treating a
113
- * gap as zero silently when using subtraction).
114
- */
115
- const hasAllValues: boolean = referencedVariables.every(
116
- (variable: string) => {
117
- return typeof values[variable] === "number";
118
- },
179
+ /*
180
+ * Groups the formula is evaluated for = groups present in EVERY
181
+ * grouped variable. Ungrouped variables broadcast, so they don't
182
+ * constrain the set.
183
+ */
184
+ let commonGroupKeys: Array<string> = Array.from(
185
+ seriesBuckets[groupedVariables[0]!]!.keys(),
186
+ );
187
+
188
+ for (let index: number = 1; index < groupedVariables.length; index++) {
189
+ const buckets: Map<string, SeriesGroupBucket> =
190
+ seriesBuckets[groupedVariables[index]!]!;
191
+ commonGroupKeys = commonGroupKeys.filter((groupKey: string) => {
192
+ return buckets.has(groupKey);
193
+ });
194
+ }
195
+
196
+ if (commonGroupKeys.length === 0) {
197
+ throw new BadDataException(
198
+ `Formula "${trimmedFormula}" references grouped queries that have no series groups in common. Make sure every grouped query used by the formula is grouped by the same attributes.`,
119
199
  );
200
+ }
120
201
 
121
- if (!hasAllValues) {
122
- continue;
123
- }
202
+ /*
203
+ * Group keys are canonical "key=value|key2=value2" strings, so a
204
+ * lexicographic sort yields a stable, human-sensible series order.
205
+ */
206
+ commonGroupKeys.sort();
124
207
 
125
- let evaluated: number;
126
- try {
127
- evaluated = MetricFormulaEvaluator.evaluateRpn(rpn, values);
128
- } catch {
129
- continue;
130
- }
208
+ const resultData: Array<AggregatedModel> = [];
131
209
 
132
- if (!Number.isFinite(evaluated)) {
133
- continue;
210
+ for (const groupKey of commonGroupKeys) {
211
+ const groupLabels: JSONObject =
212
+ seriesBuckets[groupedVariables[0]!]!.get(groupKey)!.labels;
213
+
214
+ const seriesByVariable: Record<string, Array<AggregatedModel>> = {};
215
+ for (const variableName of referencedVariables) {
216
+ const buckets: Map<string, SeriesGroupBucket> =
217
+ seriesBuckets[variableName]!;
218
+ if (
219
+ MetricFormulaEvaluator.isGroupedVariable(
220
+ buckets,
221
+ variableData[variableName]!,
222
+ )
223
+ ) {
224
+ seriesByVariable[variableName] = buckets.get(groupKey)?.samples || [];
225
+ } else {
226
+ // Ungrouped variable: broadcast to every group.
227
+ seriesByVariable[variableName] =
228
+ variableData[variableName]!.result.data;
229
+ }
134
230
  }
135
231
 
136
- resultData.push({
137
- timestamp: new Date(timestampString),
138
- value: evaluated,
139
- });
232
+ resultData.push(
233
+ ...MetricFormulaEvaluator.evaluatePointwise({
234
+ rpn,
235
+ referencedVariables,
236
+ seriesByVariable,
237
+ groupAttributes: groupLabels,
238
+ }),
239
+ );
140
240
  }
141
241
 
142
242
  return { data: resultData };
@@ -203,8 +303,8 @@ export default class MetricFormulaEvaluator {
203
303
  queryConfigs: Array<MetricQueryConfigData>;
204
304
  formulaConfigs: Array<MetricFormulaConfigData>;
205
305
  results: Array<AggregatedResult>;
206
- }): Record<string, AggregatedResult> {
207
- const variableMap: Record<string, AggregatedResult> = {};
306
+ }): Record<string, VariableSeriesData> {
307
+ const variableMap: Record<string, VariableSeriesData> = {};
208
308
 
209
309
  const totalSeries: number =
210
310
  input.queryConfigs.length + input.formulaConfigs.length;
@@ -216,10 +316,17 @@ export default class MetricFormulaEvaluator {
216
316
  }
217
317
 
218
318
  let alias: string | undefined;
319
+ let groupByAttributeKeys: Array<string> = [];
320
+
219
321
  if (index < input.queryConfigs.length) {
220
322
  alias =
221
323
  input.queryConfigs[index]?.metricAliasData?.metricVariable ||
222
324
  undefined;
325
+ groupByAttributeKeys = (
326
+ input.queryConfigs[index]?.metricQueryData?.groupByAttributeKeys || []
327
+ ).filter((key: string) => {
328
+ return Boolean(key);
329
+ });
223
330
  } else {
224
331
  const formulaIndex: number = index - input.queryConfigs.length;
225
332
  alias =
@@ -231,25 +338,230 @@ export default class MetricFormulaEvaluator {
231
338
  continue;
232
339
  }
233
340
 
234
- variableMap[alias.toLowerCase()] = result;
341
+ variableMap[alias.toLowerCase()] = {
342
+ result,
343
+ groupByAttributeKeys,
344
+ };
235
345
  }
236
346
 
237
347
  return variableMap;
238
348
  }
239
349
 
350
+ /**
351
+ * Whether a variable participates in per-group evaluation (joined by
352
+ * group key) rather than broadcasting across every group. True when
353
+ * it factually carries two or more series, OR when its QUERY was
354
+ * grouped (groupByAttributeKeys) and it returned at least one series:
355
+ * a grouped query that collapsed to a single series (e.g. only one
356
+ * host reported the denominator metric in the window) must still be
357
+ * matched group-by-group — broadcasting it would silently compute
358
+ * cross-group math stamped with another group's labels. Formula
359
+ * variables and ungrouped queries carry no grouping config, so they
360
+ * keep the observed >=2 heuristic. A config-grouped variable with an
361
+ * EMPTY result intentionally classifies as ungrouped: it degrades to
362
+ * per-point gaps (empty output) instead of a structural
363
+ * no-groups-in-common error.
364
+ *
365
+ * Only consulted once the grouped path has engaged — the passthrough
366
+ * gate in evaluateFormula deliberately does NOT use this predicate,
367
+ * so single-series inputs (the metric-monitor worker's per-fingerprint
368
+ * shape) stay a byte-identical passthrough.
369
+ */
370
+ private static isGroupedVariable(
371
+ buckets: Map<string, SeriesGroupBucket> | undefined,
372
+ variable: VariableSeriesData,
373
+ ): boolean {
374
+ const bucketCount: number = buckets?.size || 0;
375
+ if (bucketCount >= 2) {
376
+ return true;
377
+ }
378
+ return bucketCount >= 1 && variable.groupByAttributeKeys.length > 0;
379
+ }
380
+
381
+ /**
382
+ * Bucket a variable's rows by series group. Query variables group by
383
+ * their configured group-by attribute keys (read from each row's
384
+ * `attributes` map — the shape both the aggregation API and the
385
+ * metric-monitor worker produce). Formula variables (and queries
386
+ * without configured keys) group by whatever scalar `attributes`
387
+ * entries their rows carry — formula outputs are stamped with exactly
388
+ * the group attributes by this evaluator, so this round-trips
389
+ * formula-of-formula references. Rows without attributes fall into a
390
+ * single ungrouped bucket.
391
+ */
392
+ private static bucketSeriesByGroup(
393
+ variable: VariableSeriesData,
394
+ ): Map<string, SeriesGroupBucket> {
395
+ const buckets: Map<string, SeriesGroupBucket> = new Map();
396
+
397
+ for (const sample of variable.result.data) {
398
+ const labels: JSONObject = MetricFormulaEvaluator.extractGroupLabels({
399
+ sample,
400
+ groupByAttributeKeys: variable.groupByAttributeKeys,
401
+ });
402
+
403
+ const groupKey: string = MetricFormulaEvaluator.computeGroupKey(labels);
404
+
405
+ const existing: SeriesGroupBucket | undefined = buckets.get(groupKey);
406
+ if (existing) {
407
+ existing.samples.push(sample);
408
+ } else {
409
+ buckets.set(groupKey, { labels, samples: [sample] });
410
+ }
411
+ }
412
+
413
+ return buckets;
414
+ }
415
+
416
+ /**
417
+ * Mirror of MetricSeriesFingerprint.extractSeriesLabels semantics
418
+ * (missing keys preserved as "" so groups stay stable when a series
419
+ * occasionally drops an attribute). Not imported from that module
420
+ * because it pulls in node's "crypto", which the browser bundles that
421
+ * ship this evaluator cannot resolve.
422
+ */
423
+ private static extractGroupLabels(input: {
424
+ sample: AggregatedModel;
425
+ groupByAttributeKeys: Array<string>;
426
+ }): JSONObject {
427
+ const labels: JSONObject = {};
428
+
429
+ const sampleAttributes: JSONObject =
430
+ ((input.sample as unknown as JSONObject)["attributes"] as
431
+ | JSONObject
432
+ | undefined) || {};
433
+
434
+ if (input.groupByAttributeKeys.length > 0) {
435
+ for (const key of input.groupByAttributeKeys) {
436
+ const value: JSONValue | undefined = sampleAttributes[key];
437
+ labels[key] = value === undefined || value === null ? "" : value;
438
+ }
439
+ return labels;
440
+ }
441
+
442
+ for (const key of Object.keys(sampleAttributes)) {
443
+ const value: JSONValue | undefined = sampleAttributes[key];
444
+ if (value === undefined || value === null) {
445
+ labels[key] = "";
446
+ continue;
447
+ }
448
+ // Nested objects/arrays can't canonicalize into a stable label.
449
+ if (typeof value === "object") {
450
+ continue;
451
+ }
452
+ labels[key] = value;
453
+ }
454
+
455
+ return labels;
456
+ }
457
+
458
+ /**
459
+ * Canonical in-memory series key: sorted "key=value" pairs. Same
460
+ * equivalence classes as MetricSeriesFingerprint.computeFingerprint
461
+ * (which hashes this exact string), without the crypto dependency.
462
+ * Empty labels — an ungrouped series — map to "".
463
+ */
464
+ private static computeGroupKey(labels: JSONObject): string {
465
+ const keys: Array<string> = Object.keys(labels).sort();
466
+
467
+ if (keys.length === 0) {
468
+ return "";
469
+ }
470
+
471
+ const parts: Array<string> = [];
472
+ for (const key of keys) {
473
+ const raw: JSONValue | undefined = labels[key];
474
+ const value: string =
475
+ raw === undefined || raw === null ? "" : String(raw);
476
+ parts.push(`${key}=${value}`);
477
+ }
478
+
479
+ return parts.join("|");
480
+ }
481
+
482
+ /**
483
+ * Join the given series on timestamp and evaluate the formula per
484
+ * point. Points missing a value for any referenced variable are
485
+ * skipped (a partial join would produce misleading numbers — e.g.
486
+ * treating a gap as zero silently when using subtraction), as are
487
+ * non-finite results like divide-by-zero. Structural formula errors
488
+ * are impossible here: the RPN's arity is validated at parse time.
489
+ */
490
+ private static evaluatePointwise(input: {
491
+ rpn: Array<Token>;
492
+ referencedVariables: Array<string>;
493
+ seriesByVariable: Record<string, Array<AggregatedModel>>;
494
+ groupAttributes?: JSONObject | undefined;
495
+ }): Array<AggregatedModel> {
496
+ const timestampIndex: Map<
497
+ string,
498
+ Record<string, number>
499
+ > = MetricFormulaEvaluator.buildTimestampIndex(
500
+ input.referencedVariables,
501
+ input.seriesByVariable,
502
+ );
503
+
504
+ const sortedTimestamps: Array<string> = Array.from(
505
+ timestampIndex.keys(),
506
+ ).sort();
507
+
508
+ const resultData: Array<AggregatedModel> = [];
509
+
510
+ for (const timestampString of sortedTimestamps) {
511
+ const values: Record<string, number> =
512
+ timestampIndex.get(timestampString) || {};
513
+
514
+ const hasAllValues: boolean = input.referencedVariables.every(
515
+ (variable: string) => {
516
+ return typeof values[variable] === "number";
517
+ },
518
+ );
519
+
520
+ if (!hasAllValues) {
521
+ continue;
522
+ }
523
+
524
+ const evaluated: number = MetricFormulaEvaluator.evaluateRpn(
525
+ input.rpn,
526
+ values,
527
+ );
528
+
529
+ if (!Number.isFinite(evaluated)) {
530
+ continue;
531
+ }
532
+
533
+ const row: AggregatedModel = {
534
+ timestamp: new Date(timestampString),
535
+ value: evaluated,
536
+ };
537
+
538
+ if (
539
+ input.groupAttributes &&
540
+ Object.keys(input.groupAttributes).length > 0
541
+ ) {
542
+ row["attributes"] = input.groupAttributes;
543
+ }
544
+
545
+ resultData.push(row);
546
+ }
547
+
548
+ return resultData;
549
+ }
550
+
240
551
  private static buildTimestampIndex(
241
552
  variables: Array<string>,
242
- variableResults: Record<string, AggregatedResult>,
553
+ seriesByVariable: Record<string, Array<AggregatedModel>>,
243
554
  ): Map<string, Record<string, number>> {
244
555
  const index: Map<string, Record<string, number>> = new Map();
245
556
 
246
557
  for (const variable of variables) {
247
- const series: AggregatedResult | undefined = variableResults[variable];
558
+ const series: Array<AggregatedModel> | undefined =
559
+ seriesByVariable[variable];
248
560
  if (!series) {
249
561
  continue;
250
562
  }
251
563
 
252
- for (const sample of series.data) {
564
+ for (const sample of series) {
253
565
  const timestampKey: string = MetricFormulaEvaluator.normalizeTimestamp(
254
566
  sample.timestamp,
255
567
  );
@@ -524,9 +836,61 @@ export default class MetricFormulaEvaluator {
524
836
  output.push(top);
525
837
  }
526
838
 
839
+ MetricFormulaEvaluator.assertValidRpn(output);
840
+
527
841
  return output;
528
842
  }
529
843
 
844
+ /**
845
+ * Verify operator arity by simulating stack depth over the RPN. This
846
+ * turns malformed expressions like "a**b", "a+" or "()" into
847
+ * descriptive parse-time errors instead of silent per-point failures
848
+ * that render as "no data".
849
+ */
850
+ private static assertValidRpn(rpn: Array<Token>): void {
851
+ let depth: number = 0;
852
+
853
+ for (const token of rpn) {
854
+ if (
855
+ token.type === TokenType.Number ||
856
+ token.type === TokenType.Variable
857
+ ) {
858
+ depth++;
859
+ continue;
860
+ }
861
+
862
+ if (token.type === TokenType.Operator) {
863
+ const operatorValue: Operator = token.value as Operator;
864
+
865
+ if (operatorValue === "u-" || operatorValue === "u+") {
866
+ if (depth < 1) {
867
+ throw new BadDataException(
868
+ `Invalid formula: unary "${operatorValue.charAt(1)}" is missing its operand.`,
869
+ );
870
+ }
871
+ continue;
872
+ }
873
+
874
+ if (depth < 2) {
875
+ throw new BadDataException(
876
+ `Invalid formula: operator "${operatorValue}" is missing an operand.`,
877
+ );
878
+ }
879
+ depth--;
880
+ }
881
+ }
882
+
883
+ if (depth === 0) {
884
+ throw new BadDataException("Invalid formula: expression is empty.");
885
+ }
886
+
887
+ if (depth !== 1) {
888
+ throw new BadDataException(
889
+ "Invalid formula: expression does not reduce to a single value. Did you forget an operator between two values?",
890
+ );
891
+ }
892
+ }
893
+
530
894
  private static evaluateRpn(
531
895
  rpn: Array<Token>,
532
896
  variableValues: Record<string, number>,