@oneuptime/common 11.5.9 → 11.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/Models/AnalyticsModels/Index.ts +13 -0
  2. package/Models/AnalyticsModels/MetricItemAggMV1mByContainer.ts +178 -0
  3. package/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.ts +179 -0
  4. package/Models/AnalyticsModels/MetricItemAggMV1mByService.ts +179 -0
  5. package/Models/AnalyticsModels/NetworkFlow.ts +397 -0
  6. package/Models/DatabaseModels/EnterpriseLicenseInstance.ts +18 -0
  7. package/Models/DatabaseModels/GlobalConfig.ts +36 -0
  8. package/Models/DatabaseModels/Index.ts +2 -0
  9. package/Models/DatabaseModels/MarketingConversion.ts +198 -0
  10. package/Models/DatabaseModels/MetricSavedView.ts +34 -0
  11. package/Models/DatabaseModels/MetricType.ts +74 -0
  12. package/Models/DatabaseModels/NetworkDevice.ts +332 -0
  13. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +113 -0
  14. package/Models/DatabaseModels/NetworkInterface.ts +58 -0
  15. package/Models/DatabaseModels/Project.ts +37 -0
  16. package/Models/DatabaseModels/User.ts +37 -0
  17. package/Server/API/BaseAnalyticsAPI.ts +23 -0
  18. package/Server/API/EnterpriseLicenseAPI.ts +14 -0
  19. package/Server/EnvironmentConfig.ts +84 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.ts +38 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.ts +28 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.ts +108 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.ts +31 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.ts +29 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.ts +35 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  27. package/Server/Services/AnalyticsDatabaseService.ts +70 -1
  28. package/Server/Services/IncidentService.ts +13 -0
  29. package/Server/Services/Index.ts +10 -0
  30. package/Server/Services/MarketingConversionService.ts +10 -0
  31. package/Server/Services/MetricItemAggMV1mByContainerService.ts +31 -0
  32. package/Server/Services/MetricItemAggMV1mByK8sClusterService.ts +31 -0
  33. package/Server/Services/MetricItemAggMV1mByServiceService.ts +31 -0
  34. package/Server/Services/MetricService.ts +970 -122
  35. package/Server/Services/MonitorService.ts +14 -0
  36. package/Server/Services/NetworkDeviceOwnerTeamService.ts +42 -0
  37. package/Server/Services/NetworkDeviceOwnerUserService.ts +106 -0
  38. package/Server/Services/NetworkFlowService.ts +11 -0
  39. package/Server/Services/OnCallDutyPolicyService.ts +11 -1
  40. package/Server/Services/ProjectService.ts +136 -0
  41. package/Server/Services/SpanService.ts +13 -9
  42. package/Server/Services/StatusPageService.ts +10 -0
  43. package/Server/Services/TeamMemberService.ts +11 -0
  44. package/Server/Services/UserService.ts +59 -0
  45. package/Server/Types/AnalyticsDatabase/AggregateBy.ts +37 -7
  46. package/Server/Utils/Attribution.ts +99 -0
  47. package/Server/Utils/Marketing/ConversionUploadProvider.ts +103 -0
  48. package/Server/Utils/Marketing/ConversionUploadProviders.ts +22 -0
  49. package/Server/Utils/Marketing/Providers/GoogleAds.ts +270 -0
  50. package/Server/Utils/Marketing/Providers/LinkedIn.ts +147 -0
  51. package/Server/Utils/Marketing/Providers/Meta.ts +148 -0
  52. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +196 -0
  53. package/Server/Utils/Marketing/Providers/Reddit.ts +178 -0
  54. package/Server/Utils/Monitor/MonitorAlert.ts +71 -7
  55. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +31 -19
  56. package/Server/Utils/Monitor/MonitorIncident.ts +71 -7
  57. package/Server/Utils/Monitor/MonitorMetricUtil.ts +57 -0
  58. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +94 -0
  59. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +15 -0
  60. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +125 -14
  61. package/Server/Utils/ProductAnalytics.ts +133 -0
  62. package/Server/Utils/Telemetry/Telemetry.ts +39 -0
  63. package/Server/Utils/Telemetry/TelemetryEntity.ts +21 -0
  64. package/Tests/Server/API/BaseAnalyticsAPI.test.ts +72 -0
  65. package/Tests/Server/Infrastructure/SemaphorePermit.test.ts +9 -1
  66. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +21 -2
  67. package/Tests/Server/Services/MetricEntityMVKeyParity.test.ts +173 -0
  68. package/Tests/Server/Services/MetricServiceAggregate.test.ts +1391 -0
  69. package/Tests/Server/Services/NetworkDeviceOwnerServices.test.ts +260 -0
  70. package/Tests/Server/Utils/Monitor/MonitorTemplateUtilNetworkDevice.test.ts +389 -0
  71. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +764 -0
  72. package/Tests/Types/BaseDatabase/AggregationIntervalUtil.test.ts +111 -2
  73. package/Tests/Types/Database/EndsWith.test.ts +64 -0
  74. package/Tests/Types/Database/GreaterThan.test.ts +62 -0
  75. package/Tests/Types/Database/GreaterThanOrEqual.test.ts +65 -0
  76. package/Tests/Types/Database/GreaterThanOrNull.test.ts +63 -0
  77. package/Tests/Types/Database/Includes.test.ts +65 -0
  78. package/Tests/Types/Database/IncludesAll.test.ts +65 -0
  79. package/Tests/Types/Database/IncludesNone.test.ts +65 -0
  80. package/Tests/Types/Database/IsNull.test.ts +44 -0
  81. package/Tests/Types/Database/LessThan.test.ts +62 -0
  82. package/Tests/Types/Database/LessThanOrEqual.test.ts +62 -0
  83. package/Tests/Types/Database/LessThanOrNull.test.ts +62 -0
  84. package/Tests/Types/Database/MultiSearch.test.ts +81 -0
  85. package/Tests/Types/Database/NotContains.test.ts +64 -0
  86. package/Tests/Types/Database/NotNull.test.ts +44 -0
  87. package/Tests/Types/Database/StartsWith.test.ts +64 -0
  88. package/Tests/Types/Monitor/MonitorStepSqlMonitor.test.ts +83 -1
  89. package/Tests/Types/Monitor/SnmpV3EnumParsing.test.ts +247 -0
  90. package/Tests/Types/Monitor/SnmpVendorTemplate.test.ts +263 -0
  91. package/Tests/UI/Components/XAxis.test.ts +5 -3
  92. package/Tests/Utils/EnterpriseLicenseUsage.test.ts +76 -0
  93. package/Tests/Utils/Metrics/MetricExplorerUrl.test.ts +622 -0
  94. package/Tests/Utils/Metrics/MetricFormulaEvaluator.test.ts +474 -0
  95. package/Tests/Utils/Telemetry/HeartbeatAvailability.test.ts +52 -4
  96. package/Types/AnalyticsDatabase/AnalyticsTableName.ts +11 -0
  97. package/Types/BaseDatabase/AggregateBy.ts +31 -2
  98. package/Types/BaseDatabase/AggregatedResult.ts +22 -0
  99. package/Types/BaseDatabase/AggregationInterval.ts +11 -0
  100. package/Types/BaseDatabase/AggregationIntervalUtil.ts +30 -5
  101. package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +16 -0
  102. package/Types/Email/EmailTemplateType.ts +3 -0
  103. package/Types/Marketing/MarketingConversion.ts +11 -0
  104. package/Types/Metrics/MetricQueryConfigData.ts +21 -0
  105. package/Types/Metrics/MetricQueryData.ts +8 -0
  106. package/Types/Metrics/MetricViewData.ts +8 -0
  107. package/Types/Monitor/MonitorMetricType.ts +8 -0
  108. package/Types/Monitor/MonitorStep.ts +9 -0
  109. package/Types/Monitor/MonitorStepSqlMonitor.ts +12 -0
  110. package/Types/Monitor/MonitorType.ts +2 -1
  111. package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +17 -12
  112. package/Types/Monitor/SnmpMonitor/CdpNeighbor.ts +13 -0
  113. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +37 -3
  114. package/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.ts +46 -0
  115. package/Types/Monitor/SnmpMonitor/SnmpEntityInfo.ts +15 -0
  116. package/Types/Monitor/SnmpMonitor/SnmpInterface.ts +8 -0
  117. package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +17 -8
  118. package/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.ts +53 -0
  119. package/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.ts +43 -0
  120. package/Types/Monitor/SnmpMonitor/SnmpSystemInfo.ts +16 -0
  121. package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +119 -3
  122. package/Types/NetFlow/NetworkFlowRecord.ts +25 -0
  123. package/Types/Syslog/SyslogMessage.ts +18 -0
  124. package/Types/Telemetry/TelemetrySavedViewState.ts +9 -0
  125. package/Types/Telemetry/TelemetrySavedViewType.ts +12 -0
  126. package/UI/Components/Charts/Area/AreaChart.tsx +51 -0
  127. package/UI/Components/Charts/Bar/BarChart.tsx +51 -1
  128. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +97 -26
  129. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +328 -1
  130. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +115 -0
  131. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +328 -1
  132. package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +7 -0
  133. package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +15 -0
  134. package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +13 -0
  135. package/UI/Components/Charts/Line/LineChart.tsx +51 -0
  136. package/UI/Components/Charts/Types/ReferenceRegionProps.ts +12 -0
  137. package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +12 -0
  138. package/UI/Components/Charts/Types/XAxis/XAxisPrecision.ts +1 -0
  139. package/UI/Components/Charts/Utils/DataPoint.ts +0 -0
  140. package/UI/Components/Charts/Utils/TimeAnnotation.ts +169 -0
  141. package/UI/Components/Charts/Utils/XAxis.ts +28 -4
  142. package/UI/Components/Icon/Icon.tsx +33 -13
  143. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +9 -0
  144. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +67 -0
  145. package/UI/Components/Page/ModelPage.tsx +6 -1
  146. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +33 -4
  147. package/UI/Styles/Theme.css +10 -0
  148. package/UI/Utils/User.ts +41 -2
  149. package/Utils/Analytics.ts +8 -6
  150. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +74 -0
  151. package/Utils/Metrics/MetricExplorerUrl.ts +771 -0
  152. package/Utils/Metrics/MetricFormulaEvaluator.ts +410 -46
  153. package/Utils/Monitor/NetworkTopologyUtil.ts +261 -49
  154. package/Utils/ValueFormatter.ts +22 -1
  155. package/build/dist/Models/AnalyticsModels/Index.js +13 -0
  156. package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
  157. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js +159 -0
  158. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js.map +1 -0
  159. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js +158 -0
  160. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js.map +1 -0
  161. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js +160 -0
  162. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js.map +1 -0
  163. package/build/dist/Models/AnalyticsModels/NetworkFlow.js +351 -0
  164. package/build/dist/Models/AnalyticsModels/NetworkFlow.js.map +1 -0
  165. package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js +19 -0
  166. package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js.map +1 -1
  167. package/build/dist/Models/DatabaseModels/GlobalConfig.js +38 -0
  168. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  169. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  170. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  171. package/build/dist/Models/DatabaseModels/MarketingConversion.js +219 -0
  172. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +1 -0
  173. package/build/dist/Models/DatabaseModels/MetricSavedView.js +35 -0
  174. package/build/dist/Models/DatabaseModels/MetricSavedView.js.map +1 -1
  175. package/build/dist/Models/DatabaseModels/MetricType.js +76 -0
  176. package/build/dist/Models/DatabaseModels/MetricType.js.map +1 -1
  177. package/build/dist/Models/DatabaseModels/NetworkDevice.js +341 -0
  178. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  179. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +116 -0
  180. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  181. package/build/dist/Models/DatabaseModels/NetworkInterface.js +60 -0
  182. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
  183. package/build/dist/Models/DatabaseModels/Project.js +38 -0
  184. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  185. package/build/dist/Models/DatabaseModels/User.js +38 -0
  186. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  187. package/build/dist/Server/API/BaseAnalyticsAPI.js +19 -0
  188. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  189. package/build/dist/Server/API/EnterpriseLicenseAPI.js +8 -0
  190. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  191. package/build/dist/Server/EnvironmentConfig.js +51 -0
  192. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  193. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.js +27 -0
  194. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.js.map +1 -0
  195. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.js +21 -0
  196. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.js.map +1 -0
  197. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.js +47 -0
  198. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.js.map +1 -0
  199. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.js +16 -0
  200. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.js.map +1 -0
  201. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.js +18 -0
  202. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.js.map +1 -0
  203. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.js +20 -0
  204. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.js.map +1 -0
  205. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  206. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  207. package/build/dist/Server/Services/AnalyticsDatabaseService.js +58 -4
  208. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  209. package/build/dist/Server/Services/IncidentService.js +12 -0
  210. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  211. package/build/dist/Server/Services/Index.js +10 -0
  212. package/build/dist/Server/Services/Index.js.map +1 -1
  213. package/build/dist/Server/Services/MarketingConversionService.js +9 -0
  214. package/build/dist/Server/Services/MarketingConversionService.js.map +1 -0
  215. package/build/dist/Server/Services/MetricItemAggMV1mByContainerService.js +29 -0
  216. package/build/dist/Server/Services/MetricItemAggMV1mByContainerService.js.map +1 -0
  217. package/build/dist/Server/Services/MetricItemAggMV1mByK8sClusterService.js +29 -0
  218. package/build/dist/Server/Services/MetricItemAggMV1mByK8sClusterService.js.map +1 -0
  219. package/build/dist/Server/Services/MetricItemAggMV1mByServiceService.js +29 -0
  220. package/build/dist/Server/Services/MetricItemAggMV1mByServiceService.js.map +1 -0
  221. package/build/dist/Server/Services/MetricService.js +761 -125
  222. package/build/dist/Server/Services/MetricService.js.map +1 -1
  223. package/build/dist/Server/Services/MonitorService.js +18 -5
  224. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  225. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js +44 -0
  226. package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js.map +1 -1
  227. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js +88 -0
  228. package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js.map +1 -1
  229. package/build/dist/Server/Services/NetworkFlowService.js +9 -0
  230. package/build/dist/Server/Services/NetworkFlowService.js.map +1 -0
  231. package/build/dist/Server/Services/OnCallDutyPolicyService.js +15 -6
  232. package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
  233. package/build/dist/Server/Services/ProjectService.js +107 -6
  234. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  235. package/build/dist/Server/Services/SpanService.js +8 -6
  236. package/build/dist/Server/Services/SpanService.js.map +1 -1
  237. package/build/dist/Server/Services/StatusPageService.js +10 -0
  238. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  239. package/build/dist/Server/Services/TeamMemberService.js +11 -0
  240. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  241. package/build/dist/Server/Services/UserService.js +52 -0
  242. package/build/dist/Server/Services/UserService.js.map +1 -1
  243. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +33 -7
  244. package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
  245. package/build/dist/Server/Utils/Attribution.js +74 -0
  246. package/build/dist/Server/Utils/Attribution.js.map +1 -0
  247. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +40 -0
  248. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +1 -0
  249. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +20 -0
  250. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +1 -0
  251. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +177 -0
  252. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +1 -0
  253. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +113 -0
  254. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +1 -0
  255. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +109 -0
  256. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +1 -0
  257. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +130 -0
  258. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +1 -0
  259. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +126 -0
  260. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +1 -0
  261. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +53 -9
  262. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  263. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +21 -10
  264. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  265. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +54 -11
  266. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  267. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +43 -3
  268. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  269. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +68 -0
  270. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  271. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +15 -0
  272. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  273. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +100 -15
  274. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  275. package/build/dist/Server/Utils/ProductAnalytics.js +111 -0
  276. package/build/dist/Server/Utils/ProductAnalytics.js.map +1 -0
  277. package/build/dist/Server/Utils/Telemetry/Telemetry.js +32 -5
  278. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  279. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -0
  280. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  281. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +11 -0
  282. package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
  283. package/build/dist/Types/BaseDatabase/AggregationInterval.js +11 -0
  284. package/build/dist/Types/BaseDatabase/AggregationInterval.js.map +1 -1
  285. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +33 -5
  286. package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -1
  287. package/build/dist/Types/Email/EmailTemplateType.js +2 -0
  288. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  289. package/build/dist/Types/Marketing/MarketingConversion.js +13 -0
  290. package/build/dist/Types/Marketing/MarketingConversion.js.map +1 -0
  291. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  292. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  293. package/build/dist/Types/Monitor/MonitorStep.js +6 -0
  294. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  295. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js +3 -0
  296. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
  297. package/build/dist/Types/Monitor/MonitorType.js +2 -1
  298. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  299. package/build/dist/Types/Monitor/SnmpMonitor/CdpNeighbor.js +2 -0
  300. package/build/dist/Types/Monitor/SnmpMonitor/CdpNeighbor.js.map +1 -0
  301. package/build/dist/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.js +41 -0
  302. package/build/dist/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.js.map +1 -1
  303. package/build/dist/Types/Monitor/SnmpMonitor/SnmpEntityInfo.js +2 -0
  304. package/build/dist/Types/Monitor/SnmpMonitor/SnmpEntityInfo.js.map +1 -0
  305. package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js +48 -0
  306. package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js.map +1 -1
  307. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js +38 -0
  308. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js.map +1 -1
  309. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSystemInfo.js +2 -0
  310. package/build/dist/Types/Monitor/SnmpMonitor/SnmpSystemInfo.js.map +1 -0
  311. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +96 -3
  312. package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -1
  313. package/build/dist/Types/NetFlow/NetworkFlowRecord.js +2 -0
  314. package/build/dist/Types/NetFlow/NetworkFlowRecord.js.map +1 -0
  315. package/build/dist/Types/Syslog/SyslogMessage.js +2 -0
  316. package/build/dist/Types/Syslog/SyslogMessage.js.map +1 -0
  317. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js +0 -7
  318. package/build/dist/Types/Telemetry/TelemetrySavedViewState.js.map +1 -1
  319. package/build/dist/Types/Telemetry/TelemetrySavedViewType.js +13 -0
  320. package/build/dist/Types/Telemetry/TelemetrySavedViewType.js.map +1 -0
  321. package/build/dist/UI/Components/Charts/Area/AreaChart.js +25 -1
  322. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  323. package/build/dist/UI/Components/Charts/Bar/BarChart.js +26 -2
  324. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  325. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +36 -12
  326. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  327. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +208 -6
  328. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  329. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +52 -3
  330. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  331. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +208 -6
  332. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  333. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +6 -1
  334. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
  335. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.js +2 -0
  336. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.js.map +1 -0
  337. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.js +2 -0
  338. package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.js.map +1 -0
  339. package/build/dist/UI/Components/Charts/Line/LineChart.js +25 -1
  340. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  341. package/build/dist/UI/Components/Charts/Types/ReferenceRegionProps.js +2 -0
  342. package/build/dist/UI/Components/Charts/Types/ReferenceRegionProps.js.map +1 -0
  343. package/build/dist/UI/Components/Charts/Types/TimeReferenceLineProps.js +2 -0
  344. package/build/dist/UI/Components/Charts/Types/TimeReferenceLineProps.js.map +1 -0
  345. package/build/dist/UI/Components/Charts/Types/XAxis/XAxisPrecision.js +1 -0
  346. package/build/dist/UI/Components/Charts/Types/XAxis/XAxisPrecision.js.map +1 -1
  347. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +0 -0
  348. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  349. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +121 -0
  350. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -0
  351. package/build/dist/UI/Components/Charts/Utils/XAxis.js +27 -4
  352. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  353. package/build/dist/UI/Components/Icon/Icon.js +15 -8
  354. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  355. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  356. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +58 -0
  357. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  358. package/build/dist/UI/Components/Page/ModelPage.js +7 -1
  359. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  360. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +10 -4
  361. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
  362. package/build/dist/UI/Utils/User.js +35 -2
  363. package/build/dist/UI/Utils/User.js.map +1 -1
  364. package/build/dist/Utils/Analytics.js +8 -5
  365. package/build/dist/Utils/Analytics.js.map +1 -1
  366. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +57 -0
  367. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  368. package/build/dist/Utils/Metrics/MetricExplorerUrl.js +418 -0
  369. package/build/dist/Utils/Metrics/MetricExplorerUrl.js.map +1 -0
  370. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js +296 -37
  371. package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js.map +1 -1
  372. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +176 -40
  373. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  374. package/build/dist/Utils/ValueFormatter.js +20 -1
  375. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  376. package/package.json +2 -2
@@ -68,6 +68,7 @@ import { MonitorFeedEventType } from "../../Models/DatabaseModels/MonitorFeed";
68
68
  import { Gray500, Green500 } from "../../Types/BrandColors";
69
69
  import LabelService from "./LabelService";
70
70
  import logger, { LogAttributes } from "../Utils/Logger";
71
+ import ProductAnalytics from "../Utils/ProductAnalytics";
71
72
  import PushNotificationUtil from "../Utils/PushNotificationUtil";
72
73
  import ExceptionMessages from "../../Types/Exception/ExceptionMessages";
73
74
  import Project from "../../Models/DatabaseModels/Project";
@@ -637,6 +638,19 @@ export class Service extends DatabaseService<Model> {
637
638
  throw new BadDataException("currentMonitorStatusId is required");
638
639
  }
639
640
 
641
+ /*
642
+ * Activation event for marketing funnels. Only fires for human-created
643
+ * monitors (captureForUser skips when there is no user).
644
+ */
645
+ ProductAnalytics.captureForUser({
646
+ userId: onCreate.createBy.props.userId || createdItem.createdByUserId,
647
+ event: "server/monitor_created",
648
+ properties: {
649
+ project_id: createdItem.projectId.toString(),
650
+ monitor_type: createdItem.monitorType?.toString() || "",
651
+ },
652
+ });
653
+
640
654
  const monitor: Model | null = await this.findOneById({
641
655
  id: createdItem.id,
642
656
  select: {
@@ -1,10 +1,52 @@
1
+ import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
2
+ import ObjectID from "../../Types/ObjectID";
1
3
  import DatabaseService from "./DatabaseService";
2
4
  import Model from "../../Models/DatabaseModels/NetworkDeviceOwnerTeam";
5
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
3
6
 
4
7
  export class Service extends DatabaseService<Model> {
5
8
  public constructor() {
6
9
  super(Model);
7
10
  }
11
+
12
+ /*
13
+ * Returns the ids of all teams that own the given network device. Used to
14
+ * fan device ownership into monitor-created incidents/alerts and into the
15
+ * owner-added notification job.
16
+ */
17
+ @CaptureSpan()
18
+ public async getOwnerTeamIdsForDevice(
19
+ networkDeviceId: ObjectID,
20
+ projectId?: ObjectID | undefined,
21
+ ): Promise<Array<ObjectID>> {
22
+ const ownerTeams: Array<Model> = await this.findBy({
23
+ query: {
24
+ networkDeviceId: networkDeviceId,
25
+ /*
26
+ * Scope to the project when known so a monitor step referencing a
27
+ * device from another project can never fan out its owners.
28
+ */
29
+ ...(projectId ? { projectId: projectId } : {}),
30
+ },
31
+ select: {
32
+ _id: true,
33
+ teamId: true,
34
+ },
35
+ skip: 0,
36
+ limit: LIMIT_PER_PROJECT,
37
+ props: {
38
+ isRoot: true,
39
+ },
40
+ });
41
+
42
+ return ownerTeams
43
+ .map((ownerTeam: Model) => {
44
+ return ownerTeam.teamId!;
45
+ })
46
+ .filter((teamId: ObjectID) => {
47
+ return Boolean(teamId);
48
+ });
49
+ }
8
50
  }
9
51
 
10
52
  export default new Service();
@@ -1,10 +1,116 @@
1
+ import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
2
+ import MonitorStep from "../../Types/Monitor/MonitorStep";
3
+ import ObjectID from "../../Types/ObjectID";
1
4
  import DatabaseService from "./DatabaseService";
5
+ import NetworkDeviceOwnerTeamService from "./NetworkDeviceOwnerTeamService";
2
6
  import Model from "../../Models/DatabaseModels/NetworkDeviceOwnerUser";
7
+ import Monitor from "../../Models/DatabaseModels/Monitor";
8
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
9
+
10
+ export interface NetworkDeviceOwners {
11
+ ownerUserIds: Array<ObjectID>;
12
+ ownerTeamIds: Array<ObjectID>;
13
+ }
3
14
 
4
15
  export class Service extends DatabaseService<Model> {
5
16
  public constructor() {
6
17
  super(Model);
7
18
  }
19
+
20
+ /*
21
+ * Returns the ids of all users that own the given network device. Used to
22
+ * fan device ownership into monitor-created incidents/alerts and into the
23
+ * owner-added notification job.
24
+ */
25
+ @CaptureSpan()
26
+ public async getOwnerUserIdsForDevice(
27
+ networkDeviceId: ObjectID,
28
+ projectId?: ObjectID | undefined,
29
+ ): Promise<Array<ObjectID>> {
30
+ const ownerUsers: Array<Model> = await this.findBy({
31
+ query: {
32
+ networkDeviceId: networkDeviceId,
33
+ /*
34
+ * Scope to the project when known so a monitor step referencing a
35
+ * device from another project can never fan out its owners.
36
+ */
37
+ ...(projectId ? { projectId: projectId } : {}),
38
+ },
39
+ select: {
40
+ _id: true,
41
+ userId: true,
42
+ },
43
+ skip: 0,
44
+ limit: LIMIT_PER_PROJECT,
45
+ props: {
46
+ isRoot: true,
47
+ },
48
+ });
49
+
50
+ return ownerUsers
51
+ .map((ownerUser: Model) => {
52
+ return ownerUser.userId!;
53
+ })
54
+ .filter((userId: ObjectID) => {
55
+ return Boolean(userId);
56
+ });
57
+ }
58
+
59
+ /*
60
+ * Resolves the owner users/teams of the network device a monitor watches
61
+ * (if any). The device id lives on the monitor step config
62
+ * (step.data.networkDeviceMonitor.networkDeviceId). Prefer the step that
63
+ * produced the current probe response; fall back to the first step that
64
+ * references a device so callers without a step id still pick up owners.
65
+ * No-op (and no queries) for monitors that do not reference a device.
66
+ */
67
+ @CaptureSpan()
68
+ public async getDeviceOwnersForMonitor(data: {
69
+ monitor: Monitor;
70
+ monitorStepId?: string | undefined;
71
+ }): Promise<NetworkDeviceOwners> {
72
+ const monitorSteps: Array<MonitorStep> =
73
+ data.monitor.monitorSteps?.data?.monitorStepsInstanceArray || [];
74
+
75
+ let monitorStep: MonitorStep | undefined = undefined;
76
+
77
+ if (data.monitorStepId) {
78
+ monitorStep = monitorSteps.find((step: MonitorStep) => {
79
+ return step.id.toString() === data.monitorStepId;
80
+ });
81
+ }
82
+
83
+ if (!monitorStep?.data?.networkDeviceMonitor?.networkDeviceId) {
84
+ monitorStep = monitorSteps.find((step: MonitorStep) => {
85
+ return Boolean(step.data?.networkDeviceMonitor?.networkDeviceId);
86
+ });
87
+ }
88
+
89
+ const networkDeviceIdAsString: string | undefined =
90
+ monitorStep?.data?.networkDeviceMonitor?.networkDeviceId;
91
+
92
+ if (!networkDeviceIdAsString) {
93
+ return {
94
+ ownerUserIds: [],
95
+ ownerTeamIds: [],
96
+ };
97
+ }
98
+
99
+ const networkDeviceId: ObjectID = new ObjectID(networkDeviceIdAsString);
100
+ const projectId: ObjectID | undefined = data.monitor.projectId;
101
+
102
+ return {
103
+ ownerUserIds: await this.getOwnerUserIdsForDevice(
104
+ networkDeviceId,
105
+ projectId,
106
+ ),
107
+ ownerTeamIds:
108
+ await NetworkDeviceOwnerTeamService.getOwnerTeamIdsForDevice(
109
+ networkDeviceId,
110
+ projectId,
111
+ ),
112
+ };
113
+ }
8
114
  }
9
115
 
10
116
  export default new Service();
@@ -0,0 +1,11 @@
1
+ import ClickhouseDatabase from "../Infrastructure/ClickhouseDatabase";
2
+ import AnalyticsDatabaseService from "./AnalyticsDatabaseService";
3
+ import NetworkFlow from "../../Models/AnalyticsModels/NetworkFlow";
4
+
5
+ export class NetworkFlowService extends AnalyticsDatabaseService<NetworkFlow> {
6
+ public constructor(clickhouseDatabase?: ClickhouseDatabase | undefined) {
7
+ super({ modelType: NetworkFlow, database: clickhouseDatabase });
8
+ }
9
+ }
10
+
11
+ export default new NetworkFlowService();
@@ -31,6 +31,7 @@ import WorkspaceNotificationRuleService, {
31
31
  MessageBlocksByWorkspaceType,
32
32
  } from "./WorkspaceNotificationRuleService";
33
33
  import logger, { LogAttributes } from "../Utils/Logger";
34
+ import ProductAnalytics from "../Utils/ProductAnalytics";
34
35
  import OnCallDutyPolicyWorkspaceMessages from "../Utils/Workspace/WorkspaceMessages/OnCallDutyPolicy";
35
36
  import OnCallDutyPolicyFeedService from "./OnCallDutyPolicyFeedService";
36
37
  import { OnCallDutyPolicyFeedEventType } from "../../Models/DatabaseModels/OnCallDutyPolicyFeed";
@@ -44,13 +45,22 @@ export class Service extends DatabaseService<OnCallDutyPolicy> {
44
45
  }
45
46
 
46
47
  protected override async onCreateSuccess(
47
- _onCreate: OnCreate<OnCallDutyPolicy>,
48
+ onCreate: OnCreate<OnCallDutyPolicy>,
48
49
  createdItem: OnCallDutyPolicy,
49
50
  ): Promise<OnCallDutyPolicy> {
50
51
  if (!createdItem.id) {
51
52
  throw new BadDataException("On Call Policy id not found.");
52
53
  }
53
54
 
55
+ // Activation event for marketing funnels.
56
+ ProductAnalytics.captureForUser({
57
+ userId: onCreate.createBy.props.userId || createdItem.createdByUserId,
58
+ event: "server/on_call_policy_created",
59
+ properties: {
60
+ project_id: createdItem.projectId?.toString() || "",
61
+ },
62
+ });
63
+
54
64
  if (createdItem.projectId) {
55
65
  try {
56
66
  await OnCallDutyPolicyLabelRuleEngineService.applyRulesToOnCallDutyPolicy(
@@ -15,6 +15,7 @@ import QueryHelper from "../Types/Database/QueryHelper";
15
15
  import UpdateBy from "../Types/Database/UpdateBy";
16
16
  import logger, { LogAttributes } from "../Utils/Logger";
17
17
  import Errors from "../Utils/Errors";
18
+ import ProductAnalytics from "../Utils/ProductAnalytics";
18
19
  import AccessTokenService from "./AccessTokenService";
19
20
  import BillingService from "./BillingService";
20
21
  import DatabaseService from "./DatabaseService";
@@ -55,6 +56,7 @@ import EmailTemplateType from "../../Types/Email/EmailTemplateType";
55
56
  import BadDataException from "../../Types/Exception/BadDataException";
56
57
  import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
57
58
  import IconProp from "../../Types/Icon/IconProp";
59
+ import { JSONObject } from "../../Types/JSON";
58
60
  import ObjectID from "../../Types/ObjectID";
59
61
  import Permission from "../../Types/Permission";
60
62
  import IncidentSeverity from "../../Models/DatabaseModels/IncidentSeverity";
@@ -169,6 +171,8 @@ export class ProjectService extends DatabaseService<Model> {
169
171
  utmTerm: true,
170
172
  utmContent: true,
171
173
  utmUrl: true,
174
+ clickIds: true,
175
+ firstTouchAttribution: true,
172
176
  },
173
177
  props: {
174
178
  isRoot: true,
@@ -324,6 +328,10 @@ export class ProjectService extends DatabaseService<Model> {
324
328
  data.data.utmContent = user.utmContent!;
325
329
  data.data.utmUrl = user.utmUrl!;
326
330
 
331
+ // Ad attribution info (click IDs + first touch).
332
+ data.data.clickIds = user.clickIds!;
333
+ data.data.firstTouchAttribution = user.firstTouchAttribution!;
334
+
327
335
  // Set default number prefixes.
328
336
  if (!data.data.incidentNumberPrefix) {
329
337
  data.data.incidentNumberPrefix = "INC-";
@@ -477,6 +485,11 @@ export class ProjectService extends DatabaseService<Model> {
477
485
  paymentProviderPlanId: true,
478
486
  trialEndsAt: true,
479
487
  paymentProviderCustomerId: true,
488
+ createdOwnerEmail: true,
489
+ utmSource: true,
490
+ utmMedium: true,
491
+ utmCampaign: true,
492
+ clickIds: true,
480
493
  },
481
494
  props: {
482
495
  isRoot: true,
@@ -583,9 +596,116 @@ export class ProjectService extends DatabaseService<Model> {
583
596
  },
584
597
  });
585
598
 
599
+ this.capturePlanChangeAnalytics({
600
+ project: project,
601
+ newPlan: plan,
602
+ newPlanId: params.paymentProviderPlanId,
603
+ seats: seats,
604
+ });
605
+
586
606
  await this.sendSubscriptionChangeWebhookSlackNotification(project.id!);
587
607
  }
588
608
 
609
+ /*
610
+ * The paid-conversion event for ad platforms: fires server-side (immune to
611
+ * ad blockers) whenever a project's subscription plan changes, with enough
612
+ * detail (plan amounts, attribution) for revenue reporting and offline
613
+ * conversion uploads.
614
+ *
615
+ * Upgrade/downgrade is classified by plan tier (getPlanOrder), not price:
616
+ * monthly<->yearly switches of the same tier and custom-pricing plans
617
+ * (amount sentinel -1) would misclassify on price comparison.
618
+ */
619
+ private capturePlanChangeAnalytics(data: {
620
+ project: Model;
621
+ newPlan: SubscriptionPlan;
622
+ newPlanId: string;
623
+ seats: number;
624
+ }): void {
625
+ if (!data.project.createdOwnerEmail) {
626
+ return;
627
+ }
628
+
629
+ const oldPlanId: string | undefined =
630
+ data.project.paymentProviderPlanId || undefined;
631
+
632
+ // Re-submitting the currently active plan is a no-op, not a plan change.
633
+ if (oldPlanId === data.newPlanId) {
634
+ return;
635
+ }
636
+
637
+ const oldPlan: SubscriptionPlan | undefined = oldPlanId
638
+ ? SubscriptionPlan.getSubscriptionPlanById(oldPlanId, getAllEnvVars())
639
+ : undefined;
640
+
641
+ // Per-month amount, or null when unknown (custom pricing / unknown plan).
642
+ const getMonthlyAmountInUSD: (
643
+ plan: SubscriptionPlan | undefined,
644
+ planId: string | undefined,
645
+ ) => number | null = (
646
+ plan: SubscriptionPlan | undefined,
647
+ planId: string | undefined,
648
+ ): number | null => {
649
+ if (!plan || !planId || plan.isCustomPricing()) {
650
+ return null;
651
+ }
652
+ return plan.getYearlyPlanId() === planId
653
+ ? plan.getYearlySubscriptionAmountInUSD()
654
+ : plan.getMonthlySubscriptionAmountInUSD();
655
+ };
656
+
657
+ const oldMonthlyAmountInUSD: number | null = getMonthlyAmountInUSD(
658
+ oldPlan,
659
+ oldPlanId,
660
+ );
661
+ const newMonthlyAmountInUSD: number | null = getMonthlyAmountInUSD(
662
+ data.newPlan,
663
+ data.newPlanId,
664
+ );
665
+
666
+ const oldPlanOrder: number | null = oldPlan ? oldPlan.getPlanOrder() : null;
667
+ const newPlanOrder: number = data.newPlan.getPlanOrder();
668
+
669
+ const newPlanIsPaid: boolean =
670
+ data.newPlan.isCustomPricing() ||
671
+ (newMonthlyAmountInUSD !== null && newMonthlyAmountInUSD > 0);
672
+
673
+ const properties: JSONObject = {
674
+ project_id: data.project.id?.toString() || "",
675
+ old_plan: oldPlan?.getName() || "",
676
+ new_plan: data.newPlan.getName(),
677
+ seats: data.seats,
678
+ is_upgrade: oldPlanOrder !== null && newPlanOrder > oldPlanOrder,
679
+ is_downgrade: oldPlanOrder !== null && newPlanOrder < oldPlanOrder,
680
+ // Same tier, different plan id: monthly<->yearly billing switch.
681
+ is_interval_change:
682
+ oldPlanOrder !== null && newPlanOrder === oldPlanOrder,
683
+ is_paid_conversion: oldMonthlyAmountInUSD === 0 && newPlanIsPaid,
684
+ has_custom_pricing: data.newPlan.isCustomPricing(),
685
+ utm_source: data.project.utmSource || "",
686
+ utm_medium: data.project.utmMedium || "",
687
+ utm_campaign: data.project.utmCampaign || "",
688
+ click_ids: data.project.clickIds || {},
689
+ };
690
+
691
+ if (oldMonthlyAmountInUSD !== null) {
692
+ properties["old_monthly_amount_in_usd"] = oldMonthlyAmountInUSD;
693
+ }
694
+
695
+ if (newMonthlyAmountInUSD !== null) {
696
+ properties["new_monthly_amount_in_usd"] = newMonthlyAmountInUSD;
697
+ // Value for ROAS reporting: monthly recurring revenue after the change.
698
+ properties["value"] = newMonthlyAmountInUSD * data.seats;
699
+ properties["currency"] = "USD";
700
+ }
701
+
702
+ ProductAnalytics.capture({
703
+ event: "server/subscription_plan_changed",
704
+ distinctId: data.project.createdOwnerEmail.toString(),
705
+ properties: properties,
706
+ });
707
+ }
708
+
589
709
  private async sendSubscriptionChangeWebhookSlackNotification(
590
710
  projectId: ObjectID,
591
711
  ): Promise<void> {
@@ -858,6 +978,22 @@ export class ProjectService extends DatabaseService<Model> {
858
978
  this.addDefaultIncidentRoles(createdItem),
859
979
  ]);
860
980
 
981
+ if (createdItem.createdOwnerEmail) {
982
+ ProductAnalytics.capture({
983
+ event: "server/project_created",
984
+ distinctId: createdItem.createdOwnerEmail.toString(),
985
+ properties: {
986
+ project_id: createdItem.id?.toString() || "",
987
+ project_name: createdItem.name?.toString() || "",
988
+ plan: createdItem.planName?.toString() || "",
989
+ utm_source: createdItem.utmSource || "",
990
+ utm_medium: createdItem.utmMedium || "",
991
+ utm_campaign: createdItem.utmCampaign || "",
992
+ click_ids: createdItem.clickIds || {},
993
+ },
994
+ });
995
+ }
996
+
861
997
  if (NotificationSlackWebhookOnCreateProject) {
862
998
  // fetch project again.
863
999
  const project: Model | null = await this.findOneById({
@@ -8,6 +8,7 @@ import AggregateBy, {
8
8
  import { SQL, Statement } from "../Utils/AnalyticsDatabase/Statement";
9
9
  import { getQuerySettings } from "../Utils/AnalyticsDatabase/QuerySettingsHelper";
10
10
  import TableColumnType from "../../Types/AnalyticsDatabase/TableColumnType";
11
+ import AggregationInterval from "../../Types/BaseDatabase/AggregationInterval";
11
12
  import AggregationType from "../../Types/BaseDatabase/AggregationType";
12
13
  import SortOrder from "../../Types/BaseDatabase/SortOrder";
13
14
  import InBetween from "../../Types/BaseDatabase/InBetween";
@@ -340,20 +341,23 @@ export class SpanService extends AnalyticsDatabaseService<Span> {
340
341
  }
341
342
  const databaseName: string = this.database.getDatasourceOptions().database!;
342
343
 
343
- const aggregationInterval: string = AggregateUtil.getAggregationInterval({
344
- startDate: aggregateBy.startTimestamp,
345
- endDate: aggregateBy.endTimestamp,
346
- }).toLowerCase();
344
+ const aggregationInterval: AggregationInterval =
345
+ AggregateUtil.getAggregationInterval({
346
+ startDate: aggregateBy.startTimestamp,
347
+ endDate: aggregateBy.endTimestamp,
348
+ });
347
349
 
348
350
  /*
349
- * Bucket expression derived from the projection key: for the minute
350
- * interval date_trunc is a no-op, for coarser intervals truncating
351
- * the minute equals truncating the raw timestamp. Aliased to the
352
- * timestamp column name so the generic result parsing applies.
351
+ * Bucket expression derived from the projection key via the shared
352
+ * interval-expression map (the sub-hour tiers are not valid
353
+ * date_trunc units): bucketing the minute-truncated timestamp
354
+ * equals bucketing the raw timestamp for every interval >= 1
355
+ * minute. Aliased to the timestamp column name so the generic
356
+ * result parsing applies.
353
357
  */
354
358
  const statement: Statement = new Statement();
355
359
  statement.append(
356
- `SELECT ${aggregateExpression} as durationUnixNano, date_trunc('${aggregationInterval}', toStartOfMinute(startTime)) as startTime`,
360
+ `SELECT ${aggregateExpression} as durationUnixNano, ${AggregateUtil.buildBucketTimestampExpression(aggregationInterval, "toStartOfMinute(startTime)")} as startTime`,
357
361
  );
358
362
  statement.append(
359
363
  SQL` FROM ${databaseName}.${this.model.tableName} WHERE projectId = ${{
@@ -7,6 +7,7 @@ import CookieUtil from "../Utils/Cookie";
7
7
  import { ExpressRequest } from "../Utils/Express";
8
8
  import JSONWebToken from "../Utils/JsonWebToken";
9
9
  import logger, { LogAttributes } from "../Utils/Logger";
10
+ import ProductAnalytics from "../Utils/ProductAnalytics";
10
11
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
11
12
  import DatabaseService from "./DatabaseService";
12
13
  import MonitorStatusService from "./MonitorStatusService";
@@ -314,6 +315,15 @@ export class Service extends DatabaseService<StatusPage> {
314
315
  onCreate: OnCreate<StatusPage>,
315
316
  createdItem: StatusPage,
316
317
  ): Promise<StatusPage> {
318
+ // Activation event for marketing funnels.
319
+ ProductAnalytics.captureForUser({
320
+ userId: onCreate.createBy.props.userId || createdItem.createdByUserId,
321
+ event: "server/status_page_created",
322
+ properties: {
323
+ project_id: createdItem.projectId?.toString() || "",
324
+ },
325
+ });
326
+
317
327
  // Execute owner assignment asynchronously
318
328
  if (
319
329
  createdItem.projectId &&
@@ -9,6 +9,7 @@ import Select from "../Types/Database/Select";
9
9
  import UpdateBy from "../Types/Database/UpdateBy";
10
10
  import Errors from "../Utils/Errors";
11
11
  import logger, { LogAttributes } from "../Utils/Logger";
12
+ import ProductAnalytics from "../Utils/ProductAnalytics";
12
13
  import AccessTokenService from "./AccessTokenService";
13
14
  import BillingService from "./BillingService";
14
15
  import DatabaseService from "./DatabaseService";
@@ -296,6 +297,16 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
296
297
  onCreate.createBy.data.projectId!,
297
298
  );
298
299
 
300
+ // Activation event for marketing funnels, attributed to the inviter.
301
+ ProductAnalytics.captureForUser({
302
+ userId: onCreate.createBy.props.userId,
303
+ event: "server/team_member_invited",
304
+ properties: {
305
+ project_id: onCreate.createBy.data.projectId?.toString() || "",
306
+ has_accepted_invitation: Boolean(createdItem.hasAcceptedInvitation),
307
+ },
308
+ });
309
+
299
310
  return createdItem;
300
311
  }
301
312
 
@@ -4,8 +4,10 @@ import {
4
4
  NotificationSlackWebhookOnCreateUser,
5
5
  } from "../EnvironmentConfig";
6
6
  import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
7
+ import CreateBy from "../Types/Database/CreateBy";
7
8
  import UpdateBy from "../Types/Database/UpdateBy";
8
9
  import DeleteBy from "../Types/Database/DeleteBy";
10
+ import Attribution from "../Utils/Attribution";
9
11
  import logger, { LogAttributes } from "../Utils/Logger";
10
12
  import DatabaseService from "./DatabaseService";
11
13
  import EmailVerificationTokenService from "./EmailVerificationTokenService";
@@ -25,12 +27,14 @@ import OneUptimeDate from "../../Types/Date";
25
27
  import Email from "../../Types/Email";
26
28
  import EmailTemplateType from "../../Types/Email/EmailTemplateType";
27
29
  import HashedString from "../../Types/HashedString";
30
+ import { JSONObject, JSONValue } from "../../Types/JSON";
28
31
  import ObjectID from "../../Types/ObjectID";
29
32
  import Text from "../../Types/Text";
30
33
  import EmailVerificationToken from "../../Models/DatabaseModels/EmailVerificationToken";
31
34
  import TeamMember from "../../Models/DatabaseModels/TeamMember";
32
35
  import Model from "../../Models/DatabaseModels/User";
33
36
  import SlackUtil from "../Utils/Workspace/Slack/Slack";
37
+ import ProductAnalytics from "../Utils/ProductAnalytics";
34
38
  import UserTotpAuth from "../../Models/DatabaseModels/UserTotpAuth";
35
39
  import UserTotpAuthService from "./UserTotpAuthService";
36
40
  import UserWebAuthn from "../../Models/DatabaseModels/UserWebAuthn";
@@ -120,6 +124,38 @@ export class Service extends DatabaseService<Model> {
120
124
  );
121
125
  }
122
126
 
127
+ @CaptureSpan()
128
+ protected override async onBeforeCreate(
129
+ createBy: CreateBy<Model>,
130
+ ): Promise<OnCreate<Model>> {
131
+ /*
132
+ * clickIds / firstTouchAttribution are publicly creatable jsonb columns
133
+ * (set during signup). Unlike the varchar(500) utm columns they have no
134
+ * DB-level size bound, so whitelist keys and cap value lengths here.
135
+ */
136
+ const sanitizedClickIds: JSONObject | undefined =
137
+ Attribution.sanitizeClickIds(createBy.data.clickIds as JSONValue);
138
+
139
+ if (sanitizedClickIds) {
140
+ createBy.data.clickIds = sanitizedClickIds;
141
+ } else {
142
+ delete createBy.data.clickIds;
143
+ }
144
+
145
+ const sanitizedFirstTouchAttribution: JSONObject | undefined =
146
+ Attribution.sanitizeFirstTouchAttribution(
147
+ createBy.data.firstTouchAttribution as JSONValue,
148
+ );
149
+
150
+ if (sanitizedFirstTouchAttribution) {
151
+ createBy.data.firstTouchAttribution = sanitizedFirstTouchAttribution;
152
+ } else {
153
+ delete createBy.data.firstTouchAttribution;
154
+ }
155
+
156
+ return { createBy, carryForward: null };
157
+ }
158
+
123
159
  @CaptureSpan()
124
160
  protected override async onCreateSuccess(
125
161
  _onCreate: OnCreate<Model>,
@@ -141,6 +177,29 @@ export class Service extends DatabaseService<Model> {
141
177
  });
142
178
  }
143
179
 
180
+ /*
181
+ * Server-side signup event (ad blockers eat the client-side one). Also
182
+ * fires for users created via team invites — has_password separates
183
+ * direct signups (true) from invited users (false).
184
+ */
185
+ if (createdItem.email) {
186
+ ProductAnalytics.capture({
187
+ event: "server/user_created",
188
+ distinctId: createdItem.email.toString(),
189
+ properties: {
190
+ has_password: Boolean(createdItem.password),
191
+ utm_source: createdItem.utmSource || "",
192
+ utm_medium: createdItem.utmMedium || "",
193
+ utm_campaign: createdItem.utmCampaign || "",
194
+ utm_term: createdItem.utmTerm || "",
195
+ utm_content: createdItem.utmContent || "",
196
+ utm_url: createdItem.utmUrl || "",
197
+ click_ids: createdItem.clickIds || {},
198
+ first_touch: createdItem.firstTouchAttribution || {},
199
+ },
200
+ });
201
+ }
202
+
144
203
  // A place holder method used for overriding.
145
204
  return Promise.resolve(createdItem);
146
205
  }
@@ -38,19 +38,50 @@ export class AggregateUtil {
38
38
  return interval === AggregationInterval.Total;
39
39
  }
40
40
 
41
+ /**
42
+ * The single source of truth for "which ClickHouse expression buckets
43
+ * a timestamp at this interval". Every aggregate SQL builder (raw
44
+ * table, minute MV, per-host MV, span projections) must go through
45
+ * this instead of lowercasing the enum value into the statement:
46
+ * the calendar units happen to double as SQL unit names
47
+ * (`date_trunc('hour', ...)`), but the sub-hour tiers
48
+ * (FiveMinutes/...) are not valid units and compile to
49
+ * `toStartOfInterval(col, INTERVAL 5 MINUTE)` instead — which
50
+ * ClickHouse counts in whole intervals since the epoch, so the
51
+ * 5/15/30-minute grids are exact on the client's epoch-ms grid too.
52
+ *
53
+ * `timestampExpression` is a model-validated identifier or a builder-
54
+ * owned expression, so raw interpolation here is consistent with the
55
+ * surrounding builders. `Total` has no bucket expression (the window
56
+ * collapses into `min(col)` — see buildBucketTimestampSelect).
57
+ */
58
+ public static buildBucketTimestampExpression(
59
+ resolvedInterval: AggregationInterval,
60
+ timestampExpression: string,
61
+ ): string {
62
+ switch (resolvedInterval) {
63
+ case AggregationInterval.FiveMinutes:
64
+ return `toStartOfInterval(${timestampExpression}, INTERVAL 5 MINUTE)`;
65
+ case AggregationInterval.FifteenMinutes:
66
+ return `toStartOfInterval(${timestampExpression}, INTERVAL 15 MINUTE)`;
67
+ case AggregationInterval.ThirtyMinutes:
68
+ return `toStartOfInterval(${timestampExpression}, INTERVAL 30 MINUTE)`;
69
+ default: {
70
+ const interval: string = resolvedInterval.toLowerCase();
71
+ return `date_trunc('${interval}', toStartOfInterval(${timestampExpression}, INTERVAL 1 ${interval}))`;
72
+ }
73
+ }
74
+ }
75
+
41
76
  /**
42
77
  * The SELECT fragment that produces the bucket timestamp column,
43
78
  * already aliased to `timestampColumn`. Shared by every aggregate SQL
44
79
  * builder so the `Total` (whole-window) shape stays identical across
45
80
  * paths:
46
81
  *
47
- * - normal interval → `date_trunc('<i>', toStartOfInterval(col, INTERVAL 1 <i>)) as col`
82
+ * - normal interval → buildBucketTimestampExpression(...) `as col`
48
83
  * - Total → `min(col) as col` (one row per group; the
49
84
  * earliest sample timestamp in the window is the bucket label)
50
- *
51
- * `timestampColumn` is a model-validated identifier (see
52
- * AnalyticsDatabaseService._aggregateBy), so raw interpolation here is
53
- * consistent with the surrounding builders.
54
85
  */
55
86
  public static buildBucketTimestampSelect(
56
87
  resolvedInterval: AggregationInterval,
@@ -60,7 +91,6 @@ export class AggregateUtil {
60
91
  return `min(${timestampColumn}) as ${timestampColumn}`;
61
92
  }
62
93
 
63
- const interval: string = resolvedInterval.toLowerCase();
64
- return `date_trunc('${interval}', toStartOfInterval(${timestampColumn}, INTERVAL 1 ${interval})) as ${timestampColumn}`;
94
+ return `${AggregateUtil.buildBucketTimestampExpression(resolvedInterval, timestampColumn)} as ${timestampColumn}`;
65
95
  }
66
96
  }