@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
@@ -0,0 +1,133 @@
1
+ import { AnalyticsHost, AnalyticsKey } from "../EnvironmentConfig";
2
+ import UserService from "../Services/UserService";
3
+ import HTTPErrorResponse from "../../Types/API/HTTPErrorResponse";
4
+ import HTTPResponse from "../../Types/API/HTTPResponse";
5
+ import URL from "../../Types/API/URL";
6
+ import { JSONObject } from "../../Types/JSON";
7
+ import ObjectID from "../../Types/ObjectID";
8
+ import User from "../../Models/DatabaseModels/User";
9
+ import API from "../../Utils/API";
10
+ import logger from "./Logger";
11
+
12
+ /*
13
+ * Server-side product analytics (PostHog).
14
+ *
15
+ * Client-side events are lost to ad blockers — common with OneUptime's
16
+ * developer audience — so revenue and activation events are also captured
17
+ * here, where they cannot be blocked.
18
+ *
19
+ * Events are identified by the user's email (the same distinct id the
20
+ * frontends use via posthog.identify) so server and client events join into
21
+ * one person profile.
22
+ *
23
+ * No-ops when ANALYTICS_KEY / ANALYTICS_HOST are not configured (the default
24
+ * for self-hosted installs). Never throws — analytics must not break the
25
+ * product.
26
+ */
27
+ export default class ProductAnalytics {
28
+ public static isConfigured(): boolean {
29
+ return Boolean(AnalyticsKey && AnalyticsHost);
30
+ }
31
+
32
+ public static capture(data: {
33
+ event: string;
34
+ distinctId: string;
35
+ properties?: JSONObject | undefined;
36
+ }): void {
37
+ try {
38
+ if (!this.isConfigured()) {
39
+ return;
40
+ }
41
+
42
+ if (!data.distinctId) {
43
+ return;
44
+ }
45
+
46
+ API.post<JSONObject>({
47
+ url: URL.fromString(AnalyticsHost.toString()).addRoute("/capture/"),
48
+ data: {
49
+ api_key: AnalyticsKey,
50
+ event: data.event,
51
+ distinct_id: data.distinctId,
52
+ properties: {
53
+ source: "oneuptime-server",
54
+ ...(data.properties || {}),
55
+ },
56
+ },
57
+ })
58
+ .then((result: HTTPResponse<JSONObject> | HTTPErrorResponse) => {
59
+ /*
60
+ * API.post resolves (does not reject) on HTTP error statuses, so a
61
+ * misconfigured ANALYTICS_KEY (401) or malformed body (400) must be
62
+ * surfaced here or events vanish with no log signal.
63
+ */
64
+ if (result instanceof HTTPErrorResponse) {
65
+ logger.error(
66
+ `ProductAnalytics capture failed for event ${data.event}: HTTP ${result.statusCode} ${result.message}`,
67
+ );
68
+ }
69
+ })
70
+ .catch((err: Error) => {
71
+ logger.error("ProductAnalytics capture failed:");
72
+ logger.error(err);
73
+ });
74
+ } catch (err) {
75
+ /*
76
+ * e.g. URL.fromString throws on a malformed ANALYTICS_HOST. Analytics
77
+ * runs inside request-path hooks (signup, project create, plan change)
78
+ * and must never fail those requests.
79
+ */
80
+ logger.error("ProductAnalytics capture failed:");
81
+ logger.error(err as Error);
82
+ }
83
+ }
84
+
85
+ /*
86
+ * Capture an event attributed to a user by id, resolving the user's email
87
+ * to use as the distinct id. Skips silently when the user cannot be
88
+ * resolved (e.g. records created by probes, workflows or API keys).
89
+ */
90
+ public static captureForUser(data: {
91
+ userId: ObjectID | undefined | null;
92
+ event: string;
93
+ properties?: JSONObject | undefined;
94
+ }): void {
95
+ try {
96
+ if (!this.isConfigured()) {
97
+ return;
98
+ }
99
+
100
+ if (!data.userId) {
101
+ return;
102
+ }
103
+
104
+ UserService.findOneById({
105
+ id: data.userId,
106
+ select: {
107
+ email: true,
108
+ },
109
+ props: {
110
+ isRoot: true,
111
+ },
112
+ })
113
+ .then((user: User | null) => {
114
+ if (!user || !user.email) {
115
+ return;
116
+ }
117
+
118
+ this.capture({
119
+ event: data.event,
120
+ distinctId: user.email.toString(),
121
+ properties: data.properties,
122
+ });
123
+ })
124
+ .catch((err: Error) => {
125
+ logger.error("ProductAnalytics captureForUser failed:");
126
+ logger.error(err);
127
+ });
128
+ } catch (err) {
129
+ logger.error("ProductAnalytics captureForUser failed:");
130
+ logger.error(err as Error);
131
+ }
132
+ }
133
+ }
@@ -26,6 +26,8 @@ export default class TelemetryUtil {
26
26
  name: true,
27
27
  description: true,
28
28
  unit: true,
29
+ isMonotonic: true,
30
+ aggregationTemporality: true,
29
31
  },
30
32
  props: {
31
33
  isRoot: true,
@@ -66,6 +68,30 @@ export default class TelemetryUtil {
66
68
  metricType.unit = metricTypeInMap.unit || "";
67
69
  }
68
70
 
71
+ /*
72
+ * Counter semantics (isMonotonic / aggregationTemporality) are only
73
+ * known on OTel metric ingest paths — other callers (monitor
74
+ * metrics, heartbeat metrics) never set them, so an undefined
75
+ * incoming value means "unknown", not "clear the stored value".
76
+ */
77
+ if (
78
+ metricTypeInMap.isMonotonic !== undefined &&
79
+ metricType.isMonotonic !== metricTypeInMap.isMonotonic
80
+ ) {
81
+ isSame = false;
82
+ metricType.isMonotonic = metricTypeInMap.isMonotonic;
83
+ }
84
+
85
+ if (
86
+ metricTypeInMap.aggregationTemporality !== undefined &&
87
+ metricType.aggregationTemporality !==
88
+ metricTypeInMap.aggregationTemporality
89
+ ) {
90
+ isSame = false;
91
+ metricType.aggregationTemporality =
92
+ metricTypeInMap.aggregationTemporality;
93
+ }
94
+
69
95
  // check if services are same
70
96
 
71
97
  for (const serviceId of servicesInMap) {
@@ -92,6 +118,12 @@ export default class TelemetryUtil {
92
118
  services: metricType.services || [],
93
119
  description: metricTypeInMap.description || "",
94
120
  unit: metricTypeInMap.unit || "",
121
+ ...(metricType.isMonotonic !== undefined
122
+ ? { isMonotonic: metricType.isMonotonic }
123
+ : {}),
124
+ ...(metricType.aggregationTemporality !== undefined
125
+ ? { aggregationTemporality: metricType.aggregationTemporality }
126
+ : {}),
95
127
  },
96
128
  props: {
97
129
  isRoot: true,
@@ -104,6 +136,13 @@ export default class TelemetryUtil {
104
136
  metricType.name = metricName;
105
137
  metricType.description = metricTypeInMap.description || "";
106
138
  metricType.unit = metricTypeInMap.unit || "";
139
+ if (metricTypeInMap.isMonotonic !== undefined) {
140
+ metricType.isMonotonic = metricTypeInMap.isMonotonic;
141
+ }
142
+ if (metricTypeInMap.aggregationTemporality !== undefined) {
143
+ metricType.aggregationTemporality =
144
+ metricTypeInMap.aggregationTemporality;
145
+ }
107
146
  metricType.projectId = data.projectId;
108
147
  metricType.services = [];
109
148
 
@@ -888,3 +888,24 @@ export default class TelemetryEntity {
888
888
  return out;
889
889
  }
890
890
  }
891
+
892
+ /**
893
+ * `container.id` is the container identity (mirrors the container
894
+ * resolver above — id-only). Read-side helper in the mold of
895
+ * `EntityKey.keyForHost` & co.; it lives here rather than in the
896
+ * isomorphic EntityKey module because its only consumer today is the
897
+ * server-side container metric-rollup read path
898
+ * (`MetricService.tryBuildEntityAggregateMVStatement` against
899
+ * `MetricItemAggMV1mByContainer`), so there is no reason to widen the
900
+ * browser bundle. Pass the raw `container.id` attribute value.
901
+ */
902
+ export function keyForContainer(
903
+ projectId: string,
904
+ containerId: string,
905
+ ): string {
906
+ return computeEntityKeyShared({
907
+ projectId,
908
+ entityType: EntityType.Container,
909
+ identifyingAttributes: { "container.id": containerId },
910
+ });
911
+ }
@@ -0,0 +1,72 @@
1
+ import "../TestingUtils/Init";
2
+ import BaseAnalyticsAPI from "../../../Server/API/BaseAnalyticsAPI";
3
+ import AnalyticsDataModel from "../../../Models/AnalyticsModels/AnalyticsBaseModel/AnalyticsBaseModel";
4
+ import AggregateBy from "../../../Types/BaseDatabase/AggregateBy";
5
+ import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
6
+ import { describe, expect, it } from "@jest/globals";
7
+
8
+ describe("BaseAnalyticsAPI.clampAggregateLimit", () => {
9
+ type MakeAggregateByFunction = (
10
+ limit: unknown,
11
+ ) => AggregateBy<AnalyticsDataModel>;
12
+
13
+ const makeAggregateBy: MakeAggregateByFunction = (
14
+ limit: unknown,
15
+ ): AggregateBy<AnalyticsDataModel> => {
16
+ return { limit } as unknown as AggregateBy<AnalyticsDataModel>;
17
+ };
18
+
19
+ it("clamps a client-sent limit above LIMIT_PER_PROJECT down to LIMIT_PER_PROJECT", () => {
20
+ const aggregateBy: AggregateBy<AnalyticsDataModel> =
21
+ makeAggregateBy(999999999);
22
+
23
+ BaseAnalyticsAPI.clampAggregateLimit(aggregateBy);
24
+
25
+ expect(aggregateBy.limit).toBe(LIMIT_PER_PROJECT);
26
+ });
27
+
28
+ it("clamps limit = LIMIT_PER_PROJECT + 1", () => {
29
+ const aggregateBy: AggregateBy<AnalyticsDataModel> = makeAggregateBy(
30
+ LIMIT_PER_PROJECT + 1,
31
+ );
32
+
33
+ BaseAnalyticsAPI.clampAggregateLimit(aggregateBy);
34
+
35
+ expect(aggregateBy.limit).toBe(LIMIT_PER_PROJECT);
36
+ });
37
+
38
+ it("does NOT clamp down to 1000 — grouped charts legitimately use the full 10k", () => {
39
+ const aggregateBy: AggregateBy<AnalyticsDataModel> =
40
+ makeAggregateBy(LIMIT_PER_PROJECT);
41
+
42
+ BaseAnalyticsAPI.clampAggregateLimit(aggregateBy);
43
+
44
+ expect(aggregateBy.limit).toBe(LIMIT_PER_PROJECT);
45
+ });
46
+
47
+ it("leaves an in-range limit untouched", () => {
48
+ const aggregateBy: AggregateBy<AnalyticsDataModel> = makeAggregateBy(500);
49
+
50
+ BaseAnalyticsAPI.clampAggregateLimit(aggregateBy);
51
+
52
+ expect(aggregateBy.limit).toBe(500);
53
+ });
54
+
55
+ it("leaves an absent limit for the service layer's own defaulting", () => {
56
+ const aggregateBy: AggregateBy<AnalyticsDataModel> =
57
+ makeAggregateBy(undefined);
58
+
59
+ BaseAnalyticsAPI.clampAggregateLimit(aggregateBy);
60
+
61
+ expect(aggregateBy.limit).toBeUndefined();
62
+ });
63
+
64
+ it("leaves a non-numeric limit untouched (existing validation handles it)", () => {
65
+ const aggregateBy: AggregateBy<AnalyticsDataModel> =
66
+ makeAggregateBy("not-a-number");
67
+
68
+ BaseAnalyticsAPI.clampAggregateLimit(aggregateBy);
69
+
70
+ expect(aggregateBy.limit).toBe("not-a-number" as unknown as number);
71
+ });
72
+ });
@@ -36,7 +36,15 @@ function mockRedisClient(): ClientType {
36
36
  }
37
37
 
38
38
  function lastMockPermit(): MockPermit {
39
- const result: unknown = redisSemaphoreConstructor.mock.results.at(-1)?.value;
39
+ /*
40
+ * Indexed rather than .at(-1): this project targets es2017, so
41
+ * Array.prototype.at is outside its lib. Older @types/node pulled in newer
42
+ * lib references that happened to declare it, which is why this compiled
43
+ * before the types were aligned with the Node 26 runtime.
44
+ */
45
+ const results: Array<{ value: unknown }> =
46
+ redisSemaphoreConstructor.mock.results;
47
+ const result: unknown = results[results.length - 1]?.value;
40
48
  return result as MockPermit;
41
49
  }
42
50
 
@@ -364,14 +364,33 @@ describe("AnalyticsDatabaseService", () => {
364
364
  const query: string = service.toAggregateStatement(makeBaseAggregateBy())
365
365
  .statement.query;
366
366
 
367
- // 1-day window derives an Hour bucket, grouped by the time column.
367
+ /*
368
+ * 1-day window derives a FifteenMinutes bucket (see
369
+ * AggregationIntervalUtil), which compiles through the shared
370
+ * expression map — NOT via lowercasing the enum into date_trunc.
371
+ */
368
372
  expect(query).toContain(
369
- "date_trunc('hour', toStartOfInterval(column_ObjectID, INTERVAL 1 hour))",
373
+ "toStartOfInterval(column_ObjectID, INTERVAL 15 MINUTE) as column_ObjectID",
370
374
  );
375
+ expect(query).not.toContain("date_trunc('fifteenminutes'");
371
376
  expect(query).toContain("GROUP BY column_ObjectID");
372
377
  expect(query).not.toContain("min(column_ObjectID)");
373
378
  });
374
379
 
380
+ test("derives an Hour bucket for a 5-day window", () => {
381
+ const query: string = service.toAggregateStatement(
382
+ makeBaseAggregateBy({
383
+ startTimestamp: new Date("2024-01-01"),
384
+ endTimestamp: new Date("2024-01-06"),
385
+ }),
386
+ ).statement.query;
387
+
388
+ expect(query).toContain(
389
+ "date_trunc('hour', toStartOfInterval(column_ObjectID, INTERVAL 1 hour))",
390
+ );
391
+ expect(query).toContain("GROUP BY column_ObjectID");
392
+ });
393
+
375
394
  test("Total with no group-by drops the time bucket and guards empty windows", () => {
376
395
  const query: string = service.toAggregateStatement(
377
396
  makeBaseAggregateBy({ aggregationInterval: "Total" }),
@@ -0,0 +1,173 @@
1
+ import TelemetryEntity, {
2
+ ExtractedEntity,
3
+ keyForContainer,
4
+ } from "../../../Server/Utils/Telemetry/TelemetryEntity";
5
+ import {
6
+ keyForHost,
7
+ keyForKubernetesCluster,
8
+ keyForService,
9
+ } from "../../../Utils/Telemetry/EntityKey";
10
+ import EntityType from "../../../Types/Telemetry/EntityType";
11
+ import { describe, expect, test } from "@jest/globals";
12
+
13
+ /*
14
+ * Pins the read-side key derivations MetricService's entity-MV routing
15
+ * uses (keyForHost / keyForKubernetesCluster / keyForContainer /
16
+ * keyForService) against the ingest side that stamps the scalar
17
+ * entity-key columns the per-entity rollup MVs group by
18
+ * (TelemetryEntity.extractEntities -> serviceEntityKey / hostEntityKey /
19
+ * k8sClusterEntityKey / containerEntityKey on MetricItemV3; the MVs copy
20
+ * the stamped column verbatim — `WHERE <key> != '' GROUP BY ... <key>`).
21
+ *
22
+ * Byte-equality between the two sides is what makes an MV lookup
23
+ * correct: a routed predicate whose key doesn't match the stamp finds
24
+ * nothing. This is the sibling of EntityKeySqlParity.test.ts (which pins
25
+ * keyForHost against ClickHouse's SQL SHA-256); the host vector below
26
+ * reuses that test's live-ClickHouse-verified literal so the ingest
27
+ * stamping stays anchored to the same externally computed value.
28
+ */
29
+ describe("entity-MV routing keys — parity with ingest-stamped scalar entity keys", () => {
30
+ const projectId: string = "proj-123";
31
+
32
+ /*
33
+ * A resource carrying all four routable identities at once, with
34
+ * casing/whitespace drift to exercise canonicalization.
35
+ */
36
+ const attributes: Record<string, string> = {
37
+ "host.name": "Web-Server-01 ",
38
+ "k8s.cluster.name": "Prod-EU-1",
39
+ "container.id": "ABC123def456",
40
+ "service.name": "Checkout",
41
+ };
42
+
43
+ type FirstOfTypeFunction = (
44
+ entities: Array<ExtractedEntity>,
45
+ entityType: EntityType,
46
+ ) => string;
47
+
48
+ /*
49
+ * Mirrors OtelIngestBaseService.scalarEntityKeysFromEntities: the
50
+ * FIRST extracted entity of a type is what lands in the scalar column
51
+ * ('' when the type is absent).
52
+ */
53
+ const firstOfType: FirstOfTypeFunction = (
54
+ entities: Array<ExtractedEntity>,
55
+ entityType: EntityType,
56
+ ): string => {
57
+ return (
58
+ entities.find((entity: ExtractedEntity) => {
59
+ return entity.entityType === entityType;
60
+ })?.entityKey || ""
61
+ );
62
+ };
63
+
64
+ test("each routable read-side key byte-matches the stamped scalar column", () => {
65
+ const entities: Array<ExtractedEntity> = TelemetryEntity.extractEntities({
66
+ projectId,
67
+ attributes,
68
+ });
69
+
70
+ expect(firstOfType(entities, EntityType.Host)).toBe(
71
+ keyForHost(projectId, "Web-Server-01 "),
72
+ );
73
+ expect(firstOfType(entities, EntityType.KubernetesCluster)).toBe(
74
+ keyForKubernetesCluster(projectId, "Prod-EU-1"),
75
+ );
76
+ expect(firstOfType(entities, EntityType.Container)).toBe(
77
+ keyForContainer(projectId, "ABC123def456"),
78
+ );
79
+ expect(firstOfType(entities, EntityType.Service)).toBe(
80
+ keyForService(projectId, "Checkout"),
81
+ );
82
+ });
83
+
84
+ test("read-side keys canonicalize exactly like ingest (spelling drift lands on one rollup stream)", () => {
85
+ const drifted: Array<ExtractedEntity> = TelemetryEntity.extractEntities({
86
+ projectId,
87
+ attributes: {
88
+ "host.name": "web-server-01",
89
+ "k8s.cluster.name": " prod-eu-1 ",
90
+ "container.id": "abc123DEF456",
91
+ "service.name": " checkout",
92
+ },
93
+ });
94
+
95
+ expect(firstOfType(drifted, EntityType.Host)).toBe(
96
+ keyForHost(projectId, "Web-Server-01 "),
97
+ );
98
+ expect(firstOfType(drifted, EntityType.KubernetesCluster)).toBe(
99
+ keyForKubernetesCluster(projectId, "Prod-EU-1"),
100
+ );
101
+ expect(firstOfType(drifted, EntityType.Container)).toBe(
102
+ keyForContainer(projectId, "ABC123def456"),
103
+ );
104
+ expect(firstOfType(drifted, EntityType.Service)).toBe(
105
+ keyForService(projectId, "Checkout"),
106
+ );
107
+ });
108
+
109
+ test("host stamping matches the live-ClickHouse-verified vector from EntityKeySqlParity", () => {
110
+ const entities: Array<ExtractedEntity> = TelemetryEntity.extractEntities({
111
+ projectId: "proj-123",
112
+ attributes: { "host.name": "Web-Server-01 " },
113
+ });
114
+
115
+ // Literal output of ClickHouse 25.7's SHA-256 SQL for this identity.
116
+ expect(firstOfType(entities, EntityType.Host)).toBe("dba90fb9cca1242e");
117
+ });
118
+
119
+ test("service.namespace forks the stamped key — the bare-name key MUST NOT be assumed (registry required)", () => {
120
+ const namespaced: Array<ExtractedEntity> = TelemetryEntity.extractEntities({
121
+ projectId,
122
+ attributes: {
123
+ "service.name": "checkout",
124
+ "service.namespace": "prod",
125
+ },
126
+ });
127
+
128
+ const stampedKey: string = firstOfType(namespaced, EntityType.Service);
129
+
130
+ // Ingest folds the namespace in ...
131
+ expect(stampedKey).toBe(keyForService(projectId, "checkout", "prod"));
132
+ /*
133
+ * ... so the bare-name derivation finds NOTHING for these rows. This
134
+ * is why MetricService resolves service key SETS from the registry
135
+ * and falls back to raw on a miss, instead of computing one key.
136
+ */
137
+ expect(stampedKey).not.toBe(keyForService(projectId, "checkout"));
138
+ });
139
+
140
+ test("a blank namespace is not identity-bearing on either side", () => {
141
+ const blankNamespace: Array<ExtractedEntity> =
142
+ TelemetryEntity.extractEntities({
143
+ projectId,
144
+ attributes: {
145
+ "service.name": "checkout",
146
+ "service.namespace": " ",
147
+ },
148
+ });
149
+
150
+ expect(firstOfType(blankNamespace, EntityType.Service)).toBe(
151
+ keyForService(projectId, "checkout"),
152
+ );
153
+ expect(keyForService(projectId, "checkout", " ")).toBe(
154
+ keyForService(projectId, "checkout"),
155
+ );
156
+ });
157
+
158
+ test("entityKeys membership (the entityScope raw predicate) contains every routable key", () => {
159
+ const membershipKeys: Array<string> = TelemetryEntity.extractEntityKeys({
160
+ projectId,
161
+ attributes,
162
+ });
163
+
164
+ for (const key of [
165
+ keyForHost(projectId, "Web-Server-01 "),
166
+ keyForKubernetesCluster(projectId, "Prod-EU-1"),
167
+ keyForContainer(projectId, "ABC123def456"),
168
+ keyForService(projectId, "Checkout"),
169
+ ]) {
170
+ expect(membershipKeys).toContain(key);
171
+ }
172
+ });
173
+ });