@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.
- package/Models/AnalyticsModels/Index.ts +13 -0
- package/Models/AnalyticsModels/MetricItemAggMV1mByContainer.ts +178 -0
- package/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.ts +179 -0
- package/Models/AnalyticsModels/MetricItemAggMV1mByService.ts +179 -0
- package/Models/AnalyticsModels/NetworkFlow.ts +397 -0
- package/Models/DatabaseModels/EnterpriseLicenseInstance.ts +18 -0
- package/Models/DatabaseModels/GlobalConfig.ts +36 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/MarketingConversion.ts +198 -0
- package/Models/DatabaseModels/MetricSavedView.ts +34 -0
- package/Models/DatabaseModels/MetricType.ts +74 -0
- package/Models/DatabaseModels/NetworkDevice.ts +332 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +113 -0
- package/Models/DatabaseModels/NetworkInterface.ts +58 -0
- package/Models/DatabaseModels/Project.ts +37 -0
- package/Models/DatabaseModels/User.ts +37 -0
- package/Server/API/BaseAnalyticsAPI.ts +23 -0
- package/Server/API/EnterpriseLicenseAPI.ts +14 -0
- package/Server/EnvironmentConfig.ts +84 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.ts +38 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.ts +108 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.ts +35 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Services/AnalyticsDatabaseService.ts +70 -1
- package/Server/Services/IncidentService.ts +13 -0
- package/Server/Services/Index.ts +10 -0
- package/Server/Services/MarketingConversionService.ts +10 -0
- package/Server/Services/MetricItemAggMV1mByContainerService.ts +31 -0
- package/Server/Services/MetricItemAggMV1mByK8sClusterService.ts +31 -0
- package/Server/Services/MetricItemAggMV1mByServiceService.ts +31 -0
- package/Server/Services/MetricService.ts +970 -122
- package/Server/Services/MonitorService.ts +14 -0
- package/Server/Services/NetworkDeviceOwnerTeamService.ts +42 -0
- package/Server/Services/NetworkDeviceOwnerUserService.ts +106 -0
- package/Server/Services/NetworkFlowService.ts +11 -0
- package/Server/Services/OnCallDutyPolicyService.ts +11 -1
- package/Server/Services/ProjectService.ts +136 -0
- package/Server/Services/SpanService.ts +13 -9
- package/Server/Services/StatusPageService.ts +10 -0
- package/Server/Services/TeamMemberService.ts +11 -0
- package/Server/Services/UserService.ts +59 -0
- package/Server/Types/AnalyticsDatabase/AggregateBy.ts +37 -7
- package/Server/Utils/Attribution.ts +99 -0
- package/Server/Utils/Marketing/ConversionUploadProvider.ts +103 -0
- package/Server/Utils/Marketing/ConversionUploadProviders.ts +22 -0
- package/Server/Utils/Marketing/Providers/GoogleAds.ts +270 -0
- package/Server/Utils/Marketing/Providers/LinkedIn.ts +147 -0
- package/Server/Utils/Marketing/Providers/Meta.ts +148 -0
- package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +196 -0
- package/Server/Utils/Marketing/Providers/Reddit.ts +178 -0
- package/Server/Utils/Monitor/MonitorAlert.ts +71 -7
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +31 -19
- package/Server/Utils/Monitor/MonitorIncident.ts +71 -7
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +57 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +94 -0
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +15 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +125 -14
- package/Server/Utils/ProductAnalytics.ts +133 -0
- package/Server/Utils/Telemetry/Telemetry.ts +39 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +21 -0
- package/Tests/Server/API/BaseAnalyticsAPI.test.ts +72 -0
- package/Tests/Server/Infrastructure/SemaphorePermit.test.ts +9 -1
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +21 -2
- package/Tests/Server/Services/MetricEntityMVKeyParity.test.ts +173 -0
- package/Tests/Server/Services/MetricServiceAggregate.test.ts +1391 -0
- package/Tests/Server/Services/NetworkDeviceOwnerServices.test.ts +260 -0
- package/Tests/Server/Utils/Monitor/MonitorTemplateUtilNetworkDevice.test.ts +389 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +764 -0
- package/Tests/Types/BaseDatabase/AggregationIntervalUtil.test.ts +111 -2
- package/Tests/Types/Database/EndsWith.test.ts +64 -0
- package/Tests/Types/Database/GreaterThan.test.ts +62 -0
- package/Tests/Types/Database/GreaterThanOrEqual.test.ts +65 -0
- package/Tests/Types/Database/GreaterThanOrNull.test.ts +63 -0
- package/Tests/Types/Database/Includes.test.ts +65 -0
- package/Tests/Types/Database/IncludesAll.test.ts +65 -0
- package/Tests/Types/Database/IncludesNone.test.ts +65 -0
- package/Tests/Types/Database/IsNull.test.ts +44 -0
- package/Tests/Types/Database/LessThan.test.ts +62 -0
- package/Tests/Types/Database/LessThanOrEqual.test.ts +62 -0
- package/Tests/Types/Database/LessThanOrNull.test.ts +62 -0
- package/Tests/Types/Database/MultiSearch.test.ts +81 -0
- package/Tests/Types/Database/NotContains.test.ts +64 -0
- package/Tests/Types/Database/NotNull.test.ts +44 -0
- package/Tests/Types/Database/StartsWith.test.ts +64 -0
- package/Tests/Types/Monitor/MonitorStepSqlMonitor.test.ts +83 -1
- package/Tests/Types/Monitor/SnmpV3EnumParsing.test.ts +247 -0
- package/Tests/Types/Monitor/SnmpVendorTemplate.test.ts +263 -0
- package/Tests/UI/Components/XAxis.test.ts +5 -3
- package/Tests/Utils/EnterpriseLicenseUsage.test.ts +76 -0
- package/Tests/Utils/Metrics/MetricExplorerUrl.test.ts +622 -0
- package/Tests/Utils/Metrics/MetricFormulaEvaluator.test.ts +474 -0
- package/Tests/Utils/Telemetry/HeartbeatAvailability.test.ts +52 -4
- package/Types/AnalyticsDatabase/AnalyticsTableName.ts +11 -0
- package/Types/BaseDatabase/AggregateBy.ts +31 -2
- package/Types/BaseDatabase/AggregatedResult.ts +22 -0
- package/Types/BaseDatabase/AggregationInterval.ts +11 -0
- package/Types/BaseDatabase/AggregationIntervalUtil.ts +30 -5
- package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +16 -0
- package/Types/Email/EmailTemplateType.ts +3 -0
- package/Types/Marketing/MarketingConversion.ts +11 -0
- package/Types/Metrics/MetricQueryConfigData.ts +21 -0
- package/Types/Metrics/MetricQueryData.ts +8 -0
- package/Types/Metrics/MetricViewData.ts +8 -0
- package/Types/Monitor/MonitorMetricType.ts +8 -0
- package/Types/Monitor/MonitorStep.ts +9 -0
- package/Types/Monitor/MonitorStepSqlMonitor.ts +12 -0
- package/Types/Monitor/MonitorType.ts +2 -1
- package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +17 -12
- package/Types/Monitor/SnmpMonitor/CdpNeighbor.ts +13 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +37 -3
- package/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.ts +46 -0
- package/Types/Monitor/SnmpMonitor/SnmpEntityInfo.ts +15 -0
- package/Types/Monitor/SnmpMonitor/SnmpInterface.ts +8 -0
- package/Types/Monitor/SnmpMonitor/SnmpMonitorResponse.ts +17 -8
- package/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.ts +53 -0
- package/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.ts +43 -0
- package/Types/Monitor/SnmpMonitor/SnmpSystemInfo.ts +16 -0
- package/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.ts +119 -3
- package/Types/NetFlow/NetworkFlowRecord.ts +25 -0
- package/Types/Syslog/SyslogMessage.ts +18 -0
- package/Types/Telemetry/TelemetrySavedViewState.ts +9 -0
- package/Types/Telemetry/TelemetrySavedViewType.ts +12 -0
- package/UI/Components/Charts/Area/AreaChart.tsx +51 -0
- package/UI/Components/Charts/Bar/BarChart.tsx +51 -1
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +97 -26
- package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +328 -1
- package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +115 -0
- package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +328 -1
- package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +7 -0
- package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +15 -0
- package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +13 -0
- package/UI/Components/Charts/Line/LineChart.tsx +51 -0
- package/UI/Components/Charts/Types/ReferenceRegionProps.ts +12 -0
- package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +12 -0
- package/UI/Components/Charts/Types/XAxis/XAxisPrecision.ts +1 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +0 -0
- package/UI/Components/Charts/Utils/TimeAnnotation.ts +169 -0
- package/UI/Components/Charts/Utils/XAxis.ts +28 -4
- package/UI/Components/Icon/Icon.tsx +33 -13
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +9 -0
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +67 -0
- package/UI/Components/Page/ModelPage.tsx +6 -1
- package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +33 -4
- package/UI/Styles/Theme.css +10 -0
- package/UI/Utils/User.ts +41 -2
- package/Utils/Analytics.ts +8 -6
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +74 -0
- package/Utils/Metrics/MetricExplorerUrl.ts +771 -0
- package/Utils/Metrics/MetricFormulaEvaluator.ts +410 -46
- package/Utils/Monitor/NetworkTopologyUtil.ts +261 -49
- package/Utils/ValueFormatter.ts +22 -1
- package/build/dist/Models/AnalyticsModels/Index.js +13 -0
- package/build/dist/Models/AnalyticsModels/Index.js.map +1 -1
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js +159 -0
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByContainer.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js +158 -0
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js +160 -0
- package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js.map +1 -0
- package/build/dist/Models/AnalyticsModels/NetworkFlow.js +351 -0
- package/build/dist/Models/AnalyticsModels/NetworkFlow.js.map +1 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js +19 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicenseInstance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +38 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MarketingConversion.js +219 -0
- package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +1 -0
- package/build/dist/Models/DatabaseModels/MetricSavedView.js +35 -0
- package/build/dist/Models/DatabaseModels/MetricSavedView.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MetricType.js +76 -0
- package/build/dist/Models/DatabaseModels/MetricType.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +341 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +116 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkInterface.js +60 -0
- package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +38 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +38 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/BaseAnalyticsAPI.js +19 -0
- package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +8 -0
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +51 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.js +27 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414522-AddCounterSemanticsToMetricType.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.js +21 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784191414600-AddViewTypeToMetricSavedView.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.js +47 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784211212164-AddNetworkDeviceInventoryAndDiscoverySchedule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784218257664-AddEnterpriseLicenseNotificationColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784293516000-AddAttributionColumnsToUserAndProject.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1784298000000-AddMarketingConversionTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +58 -4
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +12 -0
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +10 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MarketingConversionService.js +9 -0
- package/build/dist/Server/Services/MarketingConversionService.js.map +1 -0
- package/build/dist/Server/Services/MetricItemAggMV1mByContainerService.js +29 -0
- package/build/dist/Server/Services/MetricItemAggMV1mByContainerService.js.map +1 -0
- package/build/dist/Server/Services/MetricItemAggMV1mByK8sClusterService.js +29 -0
- package/build/dist/Server/Services/MetricItemAggMV1mByK8sClusterService.js.map +1 -0
- package/build/dist/Server/Services/MetricItemAggMV1mByServiceService.js +29 -0
- package/build/dist/Server/Services/MetricItemAggMV1mByServiceService.js.map +1 -0
- package/build/dist/Server/Services/MetricService.js +761 -125
- package/build/dist/Server/Services/MetricService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +18 -5
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js +44 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerTeamService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js +88 -0
- package/build/dist/Server/Services/NetworkDeviceOwnerUserService.js.map +1 -1
- package/build/dist/Server/Services/NetworkFlowService.js +9 -0
- package/build/dist/Server/Services/NetworkFlowService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyService.js +15 -6
- package/build/dist/Server/Services/OnCallDutyPolicyService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +107 -6
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/SpanService.js +8 -6
- package/build/dist/Server/Services/SpanService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +10 -0
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +11 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +52 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js +33 -7
- package/build/dist/Server/Types/AnalyticsDatabase/AggregateBy.js.map +1 -1
- package/build/dist/Server/Utils/Attribution.js +74 -0
- package/build/dist/Server/Utils/Attribution.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +40 -0
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +20 -0
- package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +177 -0
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +113 -0
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js +109 -0
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +130 -0
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +126 -0
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +53 -9
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +21 -10
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +54 -11
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +43 -3
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +68 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +15 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +100 -15
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/ProductAnalytics.js +111 -0
- package/build/dist/Server/Utils/ProductAnalytics.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +32 -5
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -0
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js +11 -0
- package/build/dist/Types/AnalyticsDatabase/AnalyticsTableName.js.map +1 -1
- package/build/dist/Types/BaseDatabase/AggregationInterval.js +11 -0
- package/build/dist/Types/BaseDatabase/AggregationInterval.js.map +1 -1
- package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js +33 -5
- package/build/dist/Types/BaseDatabase/AggregationIntervalUtil.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +2 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Marketing/MarketingConversion.js +13 -0
- package/build/dist/Types/Marketing/MarketingConversion.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
- package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +6 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js +3 -0
- package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +2 -1
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/CdpNeighbor.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/CdpNeighbor.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.js +41 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpEntityInfo.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpEntityInfo.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js +48 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js +38 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpSystemInfo.js +2 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpSystemInfo.js.map +1 -0
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js +96 -3
- package/build/dist/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.js.map +1 -1
- package/build/dist/Types/NetFlow/NetworkFlowRecord.js +2 -0
- package/build/dist/Types/NetFlow/NetworkFlowRecord.js.map +1 -0
- package/build/dist/Types/Syslog/SyslogMessage.js +2 -0
- package/build/dist/Types/Syslog/SyslogMessage.js.map +1 -0
- package/build/dist/Types/Telemetry/TelemetrySavedViewState.js +0 -7
- package/build/dist/Types/Telemetry/TelemetrySavedViewState.js.map +1 -1
- package/build/dist/Types/Telemetry/TelemetrySavedViewType.js +13 -0
- package/build/dist/Types/Telemetry/TelemetrySavedViewType.js.map +1 -0
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +25 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +26 -2
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +36 -12
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +208 -6
- package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +52 -3
- package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +208 -6
- package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +6 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.js +2 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.js.map +1 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.js +2 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.js.map +1 -0
- package/build/dist/UI/Components/Charts/Line/LineChart.js +25 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Types/ReferenceRegionProps.js +2 -0
- package/build/dist/UI/Components/Charts/Types/ReferenceRegionProps.js.map +1 -0
- package/build/dist/UI/Components/Charts/Types/TimeReferenceLineProps.js +2 -0
- package/build/dist/UI/Components/Charts/Types/TimeReferenceLineProps.js.map +1 -0
- package/build/dist/UI/Components/Charts/Types/XAxis/XAxisPrecision.js +1 -0
- package/build/dist/UI/Components/Charts/Types/XAxis/XAxisPrecision.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +0 -0
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +121 -0
- package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -0
- package/build/dist/UI/Components/Charts/Utils/XAxis.js +27 -4
- package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +15 -8
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +58 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/Page/ModelPage.js +7 -1
- package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +10 -4
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Utils/User.js +35 -2
- package/build/dist/UI/Utils/User.js.map +1 -1
- package/build/dist/Utils/Analytics.js +8 -5
- package/build/dist/Utils/Analytics.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +57 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/Metrics/MetricExplorerUrl.js +418 -0
- package/build/dist/Utils/Metrics/MetricExplorerUrl.js.map +1 -0
- package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js +296 -37
- package/build/dist/Utils/Metrics/MetricFormulaEvaluator.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +176 -40
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/ValueFormatter.js +20 -1
- package/build/dist/Utils/ValueFormatter.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import axios, { AxiosResponse } from "axios";
|
|
2
|
+
import crypto from "crypto";
|
|
3
|
+
import {
|
|
4
|
+
MetaConversionsAccessToken,
|
|
5
|
+
MetaConversionsPixelId,
|
|
6
|
+
MetaGraphApiVersion,
|
|
7
|
+
} from "../../../EnvironmentConfig";
|
|
8
|
+
import ConversionUploadProvider, {
|
|
9
|
+
ConversionSkip,
|
|
10
|
+
ConversionUploadBatchResult,
|
|
11
|
+
} from "../ConversionUploadProvider";
|
|
12
|
+
import { JSONObject } from "../../../../Types/JSON";
|
|
13
|
+
import MarketingConversion from "../../../../Models/DatabaseModels/MarketingConversion";
|
|
14
|
+
|
|
15
|
+
const REQUEST_TIMEOUT_MS: number = 30000;
|
|
16
|
+
|
|
17
|
+
// Meta rejects website events older than 7 days at upload time.
|
|
18
|
+
const META_MAX_EVENT_AGE_IN_DAYS: number = 7;
|
|
19
|
+
|
|
20
|
+
/*
|
|
21
|
+
* Meta (Facebook) Conversions API
|
|
22
|
+
* (graph.facebook.com/{version}/{pixelId}/events). Emails are SHA-256 hashed
|
|
23
|
+
* per Meta's customer-information matching spec; the raw email never leaves
|
|
24
|
+
* OneUptime. event_id is the conversion row id, so Meta deduplicates
|
|
25
|
+
* retried uploads (and browser-pixel duplicates) server-side.
|
|
26
|
+
*/
|
|
27
|
+
export default class MetaProvider extends ConversionUploadProvider {
|
|
28
|
+
public override readonly key: string = "meta";
|
|
29
|
+
public override readonly displayName: string = "Meta";
|
|
30
|
+
|
|
31
|
+
public override isConfigured(): boolean {
|
|
32
|
+
return Boolean(MetaConversionsPixelId && MetaConversionsAccessToken);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public override getSkipReason(
|
|
36
|
+
conversion: MarketingConversion,
|
|
37
|
+
): ConversionSkip | null {
|
|
38
|
+
if (!this.getClickId(conversion, "fbclid")) {
|
|
39
|
+
return {
|
|
40
|
+
reason: "No Meta click id (fbclid)",
|
|
41
|
+
isPermanent: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (this.isOlderThanDays(conversion, META_MAX_EVENT_AGE_IN_DAYS)) {
|
|
46
|
+
return {
|
|
47
|
+
reason: "Conversion older than Meta's 7-day upload window",
|
|
48
|
+
isPermanent: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private hashEmail(email: string): string {
|
|
56
|
+
return crypto
|
|
57
|
+
.createHash("sha256")
|
|
58
|
+
.update(email.trim().toLowerCase())
|
|
59
|
+
.digest("hex");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/*
|
|
63
|
+
* fbc format per Meta spec: fb.1.{creationTimeMs}.{fbclid}. We use the
|
|
64
|
+
* conversion time as creation time since the original click timestamp is
|
|
65
|
+
* not stored.
|
|
66
|
+
*/
|
|
67
|
+
private buildFbc(fbclid: string, eventAt: Date): string {
|
|
68
|
+
return `fb.1.${eventAt.getTime()}.${fbclid}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public override async upload(
|
|
72
|
+
conversions: Array<MarketingConversion>,
|
|
73
|
+
): Promise<ConversionUploadBatchResult> {
|
|
74
|
+
const data: Array<JSONObject> = conversions.map(
|
|
75
|
+
(conversion: MarketingConversion) => {
|
|
76
|
+
const eventAt: Date = conversion.conversionAt || new Date();
|
|
77
|
+
const fbclid: string = this.getClickId(conversion, "fbclid") || "";
|
|
78
|
+
|
|
79
|
+
const userData: JSONObject = {
|
|
80
|
+
fbc: this.buildFbc(fbclid, eventAt),
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (conversion.email) {
|
|
84
|
+
userData["em"] = [this.hashEmail(conversion.email)];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const isSignUp: boolean = this.isSignUp(conversion);
|
|
88
|
+
|
|
89
|
+
const payload: JSONObject = {
|
|
90
|
+
event_name: isSignUp ? "CompleteRegistration" : "Purchase",
|
|
91
|
+
event_time: Math.floor(eventAt.getTime() / 1000),
|
|
92
|
+
event_id: conversion.id!.toString(),
|
|
93
|
+
/*
|
|
94
|
+
* Not "website": website events REQUIRE client_user_agent and
|
|
95
|
+
* event_source_url, which a server-side backfill does not have —
|
|
96
|
+
* Meta rejects the whole batch without them.
|
|
97
|
+
*/
|
|
98
|
+
action_source: "other",
|
|
99
|
+
user_data: userData,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const valueInUSD: number | undefined = this.getValueInUSD(conversion);
|
|
103
|
+
|
|
104
|
+
/*
|
|
105
|
+
* Purchase events REQUIRE custom_data.value and currency — one
|
|
106
|
+
* valueless Purchase (custom-pricing plan) would 400 the entire
|
|
107
|
+
* batch. Send 0 when the value is unknown.
|
|
108
|
+
*/
|
|
109
|
+
if (!isSignUp || valueInUSD !== undefined) {
|
|
110
|
+
payload["custom_data"] = {
|
|
111
|
+
value: valueInUSD ?? 0,
|
|
112
|
+
currency: "USD",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return payload;
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const url: string = `https://graph.facebook.com/${MetaGraphApiVersion}/${MetaConversionsPixelId}/events`;
|
|
121
|
+
|
|
122
|
+
const response: AxiosResponse<JSONObject> = await axios.post(
|
|
123
|
+
url,
|
|
124
|
+
{
|
|
125
|
+
data: data,
|
|
126
|
+
access_token: MetaConversionsAccessToken,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
130
|
+
},
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const eventsReceived: number =
|
|
134
|
+
(response.data?.["events_received"] as number) || 0;
|
|
135
|
+
|
|
136
|
+
if (eventsReceived !== conversions.length) {
|
|
137
|
+
/*
|
|
138
|
+
* Retrying the whole batch is safe: event_id makes redelivery
|
|
139
|
+
* idempotent on Meta's side.
|
|
140
|
+
*/
|
|
141
|
+
throw new Error(
|
|
142
|
+
`Meta accepted ${eventsReceived} of ${conversions.length} events`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return { permanentFailures: new Map<number, string>() };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import axios, { AxiosResponse } from "axios";
|
|
2
|
+
import {
|
|
3
|
+
MicrosoftAdsAccountId,
|
|
4
|
+
MicrosoftAdsCustomerId,
|
|
5
|
+
MicrosoftAdsDeveloperToken,
|
|
6
|
+
MicrosoftAdsOAuthClientId,
|
|
7
|
+
MicrosoftAdsOAuthClientSecret,
|
|
8
|
+
MicrosoftAdsOAuthRefreshToken,
|
|
9
|
+
MicrosoftAdsPaidSubscriptionConversionName,
|
|
10
|
+
MicrosoftAdsSignUpConversionName,
|
|
11
|
+
} from "../../../EnvironmentConfig";
|
|
12
|
+
import ConversionUploadProvider, {
|
|
13
|
+
ConversionSkip,
|
|
14
|
+
ConversionUploadBatchResult,
|
|
15
|
+
} from "../ConversionUploadProvider";
|
|
16
|
+
import { JSONObject } from "../../../../Types/JSON";
|
|
17
|
+
import MarketingConversion from "../../../../Models/DatabaseModels/MarketingConversion";
|
|
18
|
+
|
|
19
|
+
const REQUEST_TIMEOUT_MS: number = 30000;
|
|
20
|
+
|
|
21
|
+
// Microsoft accepts offline conversions up to 90 days after the click.
|
|
22
|
+
const MICROSOFT_MAX_CONVERSION_AGE_IN_DAYS: number = 90;
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
* Microsoft Advertising (Bing Ads) offline conversions via the Campaign
|
|
26
|
+
* Management v13 REST surface (OfflineConversions/Apply) using msclkid.
|
|
27
|
+
* Offline conversion goals are matched by conversion NAME configured in the
|
|
28
|
+
* Microsoft Advertising UI. OAuth2 refresh-token flow against Microsoft
|
|
29
|
+
* identity platform with the msads.manage scope.
|
|
30
|
+
*/
|
|
31
|
+
export default class MicrosoftAdsProvider extends ConversionUploadProvider {
|
|
32
|
+
public override readonly key: string = "microsoft";
|
|
33
|
+
public override readonly displayName: string = "Microsoft Advertising";
|
|
34
|
+
|
|
35
|
+
private cachedAccessToken: string | null = null;
|
|
36
|
+
private cachedAccessTokenExpiresAt: number = 0;
|
|
37
|
+
|
|
38
|
+
public override isConfigured(): boolean {
|
|
39
|
+
return Boolean(
|
|
40
|
+
MicrosoftAdsDeveloperToken &&
|
|
41
|
+
MicrosoftAdsOAuthClientId &&
|
|
42
|
+
MicrosoftAdsOAuthRefreshToken &&
|
|
43
|
+
MicrosoftAdsCustomerId &&
|
|
44
|
+
MicrosoftAdsAccountId,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public override getSkipReason(
|
|
49
|
+
conversion: MarketingConversion,
|
|
50
|
+
): ConversionSkip | null {
|
|
51
|
+
if (!this.getClickId(conversion, "msclkid")) {
|
|
52
|
+
return {
|
|
53
|
+
reason: "No Microsoft click id (msclkid)",
|
|
54
|
+
isPermanent: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!this.getConversionName(conversion)) {
|
|
59
|
+
// Config gap — leave pending so it uploads once the name is configured.
|
|
60
|
+
return {
|
|
61
|
+
reason:
|
|
62
|
+
"No Microsoft Advertising conversion name configured for this conversion type",
|
|
63
|
+
isPermanent: false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (
|
|
68
|
+
this.isOlderThanDays(conversion, MICROSOFT_MAX_CONVERSION_AGE_IN_DAYS)
|
|
69
|
+
) {
|
|
70
|
+
return {
|
|
71
|
+
reason: "Conversion older than Microsoft's 90-day click window",
|
|
72
|
+
isPermanent: true,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private getConversionName(conversion: MarketingConversion): string {
|
|
80
|
+
return this.isSignUp(conversion)
|
|
81
|
+
? MicrosoftAdsSignUpConversionName
|
|
82
|
+
: MicrosoftAdsPaidSubscriptionConversionName;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private async getAccessToken(): Promise<string> {
|
|
86
|
+
if (
|
|
87
|
+
this.cachedAccessToken &&
|
|
88
|
+
Date.now() < this.cachedAccessTokenExpiresAt
|
|
89
|
+
) {
|
|
90
|
+
return this.cachedAccessToken;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const params: URLSearchParams = new URLSearchParams();
|
|
94
|
+
params.append("client_id", MicrosoftAdsOAuthClientId);
|
|
95
|
+
if (MicrosoftAdsOAuthClientSecret) {
|
|
96
|
+
params.append("client_secret", MicrosoftAdsOAuthClientSecret);
|
|
97
|
+
}
|
|
98
|
+
params.append("refresh_token", MicrosoftAdsOAuthRefreshToken);
|
|
99
|
+
params.append("grant_type", "refresh_token");
|
|
100
|
+
params.append(
|
|
101
|
+
"scope",
|
|
102
|
+
"https://ads.microsoft.com/msads.manage offline_access",
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const response: AxiosResponse<{
|
|
106
|
+
access_token?: string;
|
|
107
|
+
expires_in?: number;
|
|
108
|
+
}> = await axios.post(
|
|
109
|
+
"https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
110
|
+
params.toString(),
|
|
111
|
+
{
|
|
112
|
+
headers: {
|
|
113
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
114
|
+
},
|
|
115
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const accessToken: string | undefined = response.data?.access_token;
|
|
120
|
+
|
|
121
|
+
if (!accessToken) {
|
|
122
|
+
throw new Error("Microsoft OAuth token response had no access_token");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.cachedAccessToken = accessToken;
|
|
126
|
+
this.cachedAccessTokenExpiresAt =
|
|
127
|
+
Date.now() + ((response.data?.expires_in || 3600) - 60) * 1000;
|
|
128
|
+
|
|
129
|
+
return accessToken;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public override async upload(
|
|
133
|
+
conversions: Array<MarketingConversion>,
|
|
134
|
+
): Promise<ConversionUploadBatchResult> {
|
|
135
|
+
const accessToken: string = await this.getAccessToken();
|
|
136
|
+
|
|
137
|
+
const body: JSONObject = {
|
|
138
|
+
OfflineConversions: conversions.map((conversion: MarketingConversion) => {
|
|
139
|
+
const payload: JSONObject = {
|
|
140
|
+
MicrosoftClickId: this.getClickId(conversion, "msclkid") || "",
|
|
141
|
+
ConversionName: this.getConversionName(conversion),
|
|
142
|
+
// ISO 8601 UTC, e.g. 2026-07-18T12:34:56Z.
|
|
143
|
+
ConversionTime: (conversion.conversionAt || new Date())
|
|
144
|
+
.toISOString()
|
|
145
|
+
.replace(/\.\d{3}Z$/, "Z"),
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const valueInUSD: number | undefined = this.getValueInUSD(conversion);
|
|
149
|
+
|
|
150
|
+
if (valueInUSD !== undefined) {
|
|
151
|
+
payload["ConversionValue"] = valueInUSD;
|
|
152
|
+
payload["ConversionCurrencyCode"] = "USD";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return payload;
|
|
156
|
+
}),
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const response: AxiosResponse<JSONObject> = await axios.post(
|
|
160
|
+
"https://campaign.api.bingads.microsoft.com/CampaignManagement/v13/OfflineConversions/Apply",
|
|
161
|
+
body,
|
|
162
|
+
{
|
|
163
|
+
headers: {
|
|
164
|
+
Authorization: `Bearer ${accessToken}`,
|
|
165
|
+
DeveloperToken: MicrosoftAdsDeveloperToken,
|
|
166
|
+
CustomerId: MicrosoftAdsCustomerId,
|
|
167
|
+
CustomerAccountId: MicrosoftAdsAccountId,
|
|
168
|
+
"Content-Type": "application/json",
|
|
169
|
+
},
|
|
170
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
171
|
+
},
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
/*
|
|
175
|
+
* The Apply response reports per-item failures in PartialErrors, each
|
|
176
|
+
* carrying the Index of the failing item in the submitted array.
|
|
177
|
+
*/
|
|
178
|
+
const permanentFailures: Map<number, string> = new Map<number, string>();
|
|
179
|
+
|
|
180
|
+
const partialErrors: Array<JSONObject> =
|
|
181
|
+
(response.data?.["PartialErrors"] as Array<JSONObject>) || [];
|
|
182
|
+
|
|
183
|
+
for (const partialError of partialErrors) {
|
|
184
|
+
if (typeof partialError?.["Index"] === "number") {
|
|
185
|
+
permanentFailures.set(
|
|
186
|
+
partialError["Index"] as number,
|
|
187
|
+
`${partialError["ErrorCode"] || ""} ${
|
|
188
|
+
partialError["Message"] || "Unknown Microsoft Advertising error"
|
|
189
|
+
}`.trim(),
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return { permanentFailures };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import axios, { AxiosResponse } from "axios";
|
|
2
|
+
import crypto from "crypto";
|
|
3
|
+
import {
|
|
4
|
+
RedditAdsAccountId,
|
|
5
|
+
RedditAdsOAuthClientId,
|
|
6
|
+
RedditAdsOAuthClientSecret,
|
|
7
|
+
RedditAdsOAuthRefreshToken,
|
|
8
|
+
} from "../../../EnvironmentConfig";
|
|
9
|
+
import ConversionUploadProvider, {
|
|
10
|
+
ConversionSkip,
|
|
11
|
+
ConversionUploadBatchResult,
|
|
12
|
+
} from "../ConversionUploadProvider";
|
|
13
|
+
import { JSONObject } from "../../../../Types/JSON";
|
|
14
|
+
import MarketingConversion from "../../../../Models/DatabaseModels/MarketingConversion";
|
|
15
|
+
|
|
16
|
+
const REQUEST_TIMEOUT_MS: number = 30000;
|
|
17
|
+
|
|
18
|
+
// Reddit accepts conversion events up to 7 days old.
|
|
19
|
+
const REDDIT_MAX_EVENT_AGE_IN_DAYS: number = 7;
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Reddit Conversions API
|
|
23
|
+
* (ads-api.reddit.com/api/v2.0/conversions/events/{accountId}) using the
|
|
24
|
+
* rdt_cid click id. conversion_id (the conversion row id) makes retried
|
|
25
|
+
* uploads idempotent on Reddit's side. OAuth2 refresh-token flow with HTTP
|
|
26
|
+
* basic auth against reddit.com.
|
|
27
|
+
*/
|
|
28
|
+
export default class RedditProvider extends ConversionUploadProvider {
|
|
29
|
+
public override readonly key: string = "reddit";
|
|
30
|
+
public override readonly displayName: string = "Reddit";
|
|
31
|
+
|
|
32
|
+
private cachedAccessToken: string | null = null;
|
|
33
|
+
private cachedAccessTokenExpiresAt: number = 0;
|
|
34
|
+
|
|
35
|
+
public override isConfigured(): boolean {
|
|
36
|
+
return Boolean(
|
|
37
|
+
RedditAdsOAuthClientId &&
|
|
38
|
+
RedditAdsOAuthClientSecret &&
|
|
39
|
+
RedditAdsOAuthRefreshToken &&
|
|
40
|
+
RedditAdsAccountId,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public override getSkipReason(
|
|
45
|
+
conversion: MarketingConversion,
|
|
46
|
+
): ConversionSkip | null {
|
|
47
|
+
if (!this.getClickId(conversion, "rdt_cid")) {
|
|
48
|
+
return {
|
|
49
|
+
reason: "No Reddit click id (rdt_cid)",
|
|
50
|
+
isPermanent: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (this.isOlderThanDays(conversion, REDDIT_MAX_EVENT_AGE_IN_DAYS)) {
|
|
55
|
+
return {
|
|
56
|
+
reason: "Conversion older than Reddit's 7-day upload window",
|
|
57
|
+
isPermanent: true,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private hashEmail(email: string): string {
|
|
65
|
+
return crypto
|
|
66
|
+
.createHash("sha256")
|
|
67
|
+
.update(email.trim().toLowerCase())
|
|
68
|
+
.digest("hex");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private async getAccessToken(): Promise<string> {
|
|
72
|
+
if (
|
|
73
|
+
this.cachedAccessToken &&
|
|
74
|
+
Date.now() < this.cachedAccessTokenExpiresAt
|
|
75
|
+
) {
|
|
76
|
+
return this.cachedAccessToken;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const params: URLSearchParams = new URLSearchParams();
|
|
80
|
+
params.append("grant_type", "refresh_token");
|
|
81
|
+
params.append("refresh_token", RedditAdsOAuthRefreshToken);
|
|
82
|
+
|
|
83
|
+
const response: AxiosResponse<{
|
|
84
|
+
access_token?: string;
|
|
85
|
+
expires_in?: number;
|
|
86
|
+
}> = await axios.post(
|
|
87
|
+
"https://www.reddit.com/api/v1/access_token",
|
|
88
|
+
params.toString(),
|
|
89
|
+
{
|
|
90
|
+
auth: {
|
|
91
|
+
username: RedditAdsOAuthClientId,
|
|
92
|
+
password: RedditAdsOAuthClientSecret,
|
|
93
|
+
},
|
|
94
|
+
headers: {
|
|
95
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
96
|
+
// Reddit throttles/blocks requests without a descriptive User-Agent.
|
|
97
|
+
"User-Agent": "OneUptime-ConversionsUpload/1.0",
|
|
98
|
+
},
|
|
99
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const accessToken: string | undefined = response.data?.access_token;
|
|
104
|
+
|
|
105
|
+
if (!accessToken) {
|
|
106
|
+
throw new Error("Reddit OAuth token response had no access_token");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this.cachedAccessToken = accessToken;
|
|
110
|
+
this.cachedAccessTokenExpiresAt =
|
|
111
|
+
Date.now() + ((response.data?.expires_in || 3600) - 60) * 1000;
|
|
112
|
+
|
|
113
|
+
return accessToken;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public override async upload(
|
|
117
|
+
conversions: Array<MarketingConversion>,
|
|
118
|
+
): Promise<ConversionUploadBatchResult> {
|
|
119
|
+
const accessToken: string = await this.getAccessToken();
|
|
120
|
+
|
|
121
|
+
const events: Array<JSONObject> = conversions.map(
|
|
122
|
+
(conversion: MarketingConversion) => {
|
|
123
|
+
const eventAt: Date = conversion.conversionAt || new Date();
|
|
124
|
+
|
|
125
|
+
const eventMetadata: JSONObject = {
|
|
126
|
+
// Dedup key: retried uploads are idempotent on Reddit's side.
|
|
127
|
+
conversion_id: conversion.id!.toString(),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const valueInUSD: number | undefined = this.getValueInUSD(conversion);
|
|
131
|
+
|
|
132
|
+
if (valueInUSD !== undefined) {
|
|
133
|
+
eventMetadata["value_decimal"] = valueInUSD;
|
|
134
|
+
eventMetadata["currency"] = "USD";
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const payload: JSONObject = {
|
|
138
|
+
event_at: eventAt.toISOString(),
|
|
139
|
+
click_id: this.getClickId(conversion, "rdt_cid") || "",
|
|
140
|
+
event_type: {
|
|
141
|
+
tracking_type: this.isSignUp(conversion) ? "SignUp" : "Purchase",
|
|
142
|
+
},
|
|
143
|
+
event_metadata: eventMetadata,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (conversion.email) {
|
|
147
|
+
payload["user"] = {
|
|
148
|
+
email: this.hashEmail(conversion.email),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return payload;
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
await axios.post(
|
|
157
|
+
`https://ads-api.reddit.com/api/v2.0/conversions/events/${RedditAdsAccountId}`,
|
|
158
|
+
{
|
|
159
|
+
test_mode: false,
|
|
160
|
+
events: events,
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
headers: {
|
|
164
|
+
Authorization: `Bearer ${accessToken}`,
|
|
165
|
+
"Content-Type": "application/json",
|
|
166
|
+
},
|
|
167
|
+
timeout: REQUEST_TIMEOUT_MS,
|
|
168
|
+
},
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
/*
|
|
172
|
+
* Reddit accepts or rejects the request as a whole; request-level
|
|
173
|
+
* failures throw and the batch is retried (idempotent via
|
|
174
|
+
* conversion_id).
|
|
175
|
+
*/
|
|
176
|
+
return { permanentFailures: new Map<number, string>() };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -24,6 +24,9 @@ import AlertService from "../../Services/AlertService";
|
|
|
24
24
|
import AlertSeverityService from "../../Services/AlertSeverityService";
|
|
25
25
|
import AlertStateTimelineService from "../../Services/AlertStateTimelineService";
|
|
26
26
|
import HostService from "../../Services/HostService";
|
|
27
|
+
import NetworkDeviceOwnerUserService, {
|
|
28
|
+
NetworkDeviceOwners,
|
|
29
|
+
} from "../../Services/NetworkDeviceOwnerUserService";
|
|
27
30
|
import ServiceService from "../../Services/ServiceService";
|
|
28
31
|
import logger, { LogAttributes } from "../Logger";
|
|
29
32
|
import CaptureSpan from "../Telemetry/CaptureSpan";
|
|
@@ -300,6 +303,15 @@ export default class MonitorAlert {
|
|
|
300
303
|
? input.matchesPerSeries
|
|
301
304
|
: [undefined];
|
|
302
305
|
|
|
306
|
+
/*
|
|
307
|
+
* Owners of the network device this monitor watches (if any), resolved
|
|
308
|
+
* lazily on first alert creation and reused for the rest of the
|
|
309
|
+
* evaluation — the device is configured per monitor step, so it is
|
|
310
|
+
* constant across the criteria/series loops below. Merged into every
|
|
311
|
+
* created alert's owners alongside the criteria-configured ones.
|
|
312
|
+
*/
|
|
313
|
+
let networkDeviceOwners: NetworkDeviceOwners | null = null;
|
|
314
|
+
|
|
303
315
|
for (const criteriaAlert of input.criteriaInstance.data?.alerts || []) {
|
|
304
316
|
for (const seriesMatch of seriesToProcess) {
|
|
305
317
|
const seriesFingerprint: string | undefined = seriesMatch?.fingerprint;
|
|
@@ -627,16 +639,38 @@ export default class MonitorAlert {
|
|
|
627
639
|
},
|
|
628
640
|
});
|
|
629
641
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
642
|
+
/*
|
|
643
|
+
* Add owner teams and users after alert creation. Owners configured
|
|
644
|
+
* on the criteria template are merged (deduped) with the owners of
|
|
645
|
+
* the network device this monitor watches, so device ownership flows
|
|
646
|
+
* into the alerts its monitor raises.
|
|
647
|
+
*/
|
|
648
|
+
if (networkDeviceOwners === null) {
|
|
649
|
+
networkDeviceOwners =
|
|
650
|
+
await NetworkDeviceOwnerUserService.getDeviceOwnersForMonitor({
|
|
651
|
+
monitor: input.monitor,
|
|
652
|
+
monitorStepId: (
|
|
653
|
+
input.dataToProcess as ProbeMonitorResponse
|
|
654
|
+
).monitorStepId?.toString(),
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const ownerUserIds: Array<ObjectID> = this.mergeOwnerIds(
|
|
659
|
+
criteriaAlert.ownerUserIds || [],
|
|
660
|
+
networkDeviceOwners.ownerUserIds,
|
|
661
|
+
);
|
|
662
|
+
|
|
663
|
+
const ownerTeamIds: Array<ObjectID> = this.mergeOwnerIds(
|
|
664
|
+
criteriaAlert.ownerTeamIds || [],
|
|
665
|
+
networkDeviceOwners.ownerTeamIds,
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
if (ownerTeamIds.length || ownerUserIds.length) {
|
|
635
669
|
await AlertService.addOwners(
|
|
636
670
|
input.monitor.projectId!,
|
|
637
671
|
createdAlert.id!,
|
|
638
|
-
|
|
639
|
-
|
|
672
|
+
ownerUserIds,
|
|
673
|
+
ownerTeamIds,
|
|
640
674
|
true, // notify owners
|
|
641
675
|
{
|
|
642
676
|
isRoot: true,
|
|
@@ -658,6 +692,36 @@ export default class MonitorAlert {
|
|
|
658
692
|
}
|
|
659
693
|
}
|
|
660
694
|
|
|
695
|
+
/*
|
|
696
|
+
* Merges two owner id lists, deduping by string value. Criteria-authored
|
|
697
|
+
* ids can arrive as plain strings from stored JSON, so normalise through
|
|
698
|
+
* toString() for both the comparison and the returned ObjectIDs.
|
|
699
|
+
*/
|
|
700
|
+
private static mergeOwnerIds(
|
|
701
|
+
primary: Array<ObjectID>,
|
|
702
|
+
additional: Array<ObjectID>,
|
|
703
|
+
): Array<ObjectID> {
|
|
704
|
+
const seenIds: Set<string> = new Set<string>();
|
|
705
|
+
const mergedIds: Array<ObjectID> = [];
|
|
706
|
+
|
|
707
|
+
for (const ownerId of [...primary, ...additional]) {
|
|
708
|
+
if (!ownerId) {
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
const ownerIdAsString: string = ownerId.toString();
|
|
713
|
+
|
|
714
|
+
if (!ownerIdAsString || seenIds.has(ownerIdAsString)) {
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
seenIds.add(ownerIdAsString);
|
|
719
|
+
mergedIds.push(new ObjectID(ownerIdAsString));
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
return mergedIds;
|
|
723
|
+
}
|
|
724
|
+
|
|
661
725
|
private static async resolveOpenAlert(input: {
|
|
662
726
|
openAlert: Alert;
|
|
663
727
|
rootCause: string;
|