@oneuptime/common 12.0.32 → 12.0.33
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/Span.ts +14 -0
- package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
- package/Models/DatabaseModels/Index.ts +10 -0
- package/Models/DatabaseModels/Monitor.ts +76 -0
- package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
- package/Models/DatabaseModels/NetworkDevice.ts +176 -1
- package/Models/DatabaseModels/NetworkSite.ts +201 -2
- package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
- package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
- package/Models/DatabaseModels/TelemetryException.ts +119 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
- package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
- package/Server/API/EnterpriseLicenseAPI.ts +391 -64
- package/Server/API/LlmProviderAPI.ts +137 -22
- package/Server/EnvironmentConfig.ts +14 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Infrastructure/QueueWorker.ts +38 -8
- package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
- package/Server/Middleware/ProjectAuthorization.ts +11 -0
- package/Server/Middleware/SCIMAuthorization.ts +12 -0
- package/Server/Middleware/TelemetryIngest.ts +11 -0
- package/Server/Services/AIBillingService.ts +101 -27
- package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
- package/Server/Services/EnterpriseLicenseService.ts +55 -0
- package/Server/Services/Index.ts +10 -0
- package/Server/Services/MonitorService.ts +143 -21
- package/Server/Services/MonitorStatusTimelineService.ts +150 -8
- package/Server/Services/MonitorTemplateService.ts +217 -1
- package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
- package/Server/Services/NetworkAlertPolicyService.ts +944 -0
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +9 -10
- package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
- package/Server/Services/NetworkDeviceService.ts +1032 -73
- package/Server/Services/NetworkSiteService.ts +1502 -129
- package/Server/Services/NetworkSiteTypeService.ts +1216 -0
- package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
- package/Server/Services/NotificationService.ts +118 -28
- package/Server/Services/ProjectService.ts +105 -48
- package/Server/Services/StatusPagePrivateUserService.ts +103 -3
- package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
- package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
- package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
- package/Server/Services/UserNotificationSettingService.ts +62 -25
- package/Server/Services/UserService.ts +95 -0
- package/Server/Types/Database/QueryHelper.ts +2 -2
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
- package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
- package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
- package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
- package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
- package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
- package/Server/Utils/DataSource/HttpFetch.ts +9 -2
- package/Server/Utils/EmailRollup/EmailRollupConstants.ts +98 -0
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +872 -0
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
- package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
- package/Server/Utils/LLM/LLMService.ts +78 -0
- package/Server/Utils/LogRedaction.ts +8 -0
- package/Server/Utils/Logger.ts +79 -1
- package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
- package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +49 -0
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
- package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
- package/Server/Utils/Monitor/MonitorTemplateUtil.ts +43 -0
- package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
- package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
- package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
- package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
- package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
- package/Server/Utils/OutboundUserAgent.ts +152 -0
- package/Server/Utils/StartServer.ts +51 -19
- package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
- package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
- package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
- package/Server/Utils/Telemetry.ts +198 -51
- package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
- package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +134 -33
- package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
- package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
- package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
- package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +18 -9
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
- package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
- package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
- package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
- package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
- package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
- package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
- package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +41 -5
- package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
- package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
- package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
- package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
- package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
- package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
- package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
- package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
- package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
- package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
- package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
- package/Tests/Server/Infrastructure/Postgres/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
- package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
- package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
- package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
- package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
- package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
- package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
- package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
- package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
- package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
- package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +47 -4
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
- package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
- package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
- package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
- package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
- package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
- package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
- package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
- package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
- package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
- package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
- package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
- package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
- package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
- package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
- package/Tests/Server/Services/UserEmailChangePasswordResetExpiry.test.ts +472 -0
- package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
- package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
- package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
- package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +856 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +102 -1
- package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
- package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
- package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
- package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -0
- package/Tests/Server/Utils/Captcha.test.ts +422 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +96 -2
- package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +752 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
- package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
- package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
- package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
- package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
- package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
- package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
- package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
- package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
- package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
- package/Tests/Server/Utils/Telemetry.test.ts +456 -66
- package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
- package/Tests/Types/Monitor/MonitorStepDatabaseMonitor.test.ts +243 -0
- package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
- package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
- package/Tests/Types/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
- package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
- package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
- package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -0
- package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
- package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +15 -0
- package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
- package/Tests/UI/Components/SideMenuItem.test.tsx +226 -4
- package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
- package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -0
- package/Tests/UI/Utils/PageScrollLock.test.tsx +377 -0
- package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
- package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
- package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
- package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
- package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
- package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
- package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
- package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
- package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
- package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
- package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
- package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
- package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
- package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -0
- package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
- package/Types/AI/ExceptionAIClassification.ts +10 -24
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
- package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
- package/Types/Exception/ApiException.ts +10 -0
- package/Types/Exception/BadDataException.ts +11 -0
- package/Types/Exception/BadRequestException.ts +11 -0
- package/Types/Exception/Exception.ts +65 -0
- package/Types/Exception/ForbiddenException.ts +10 -0
- package/Types/Exception/NotAuthenticatedException.ts +10 -0
- package/Types/Exception/NotAuthorizedException.ts +10 -0
- package/Types/Exception/NotFoundException.ts +11 -0
- package/Types/Exception/PayloadTooLargeException.ts +11 -0
- package/Types/Exception/PaymentRequiredException.ts +10 -0
- package/Types/Exception/ServiceUnavailableException.ts +10 -0
- package/Types/Exception/SsoAuthorizationException.ts +10 -0
- package/Types/Exception/TenantNotFoundException.ts +11 -0
- package/Types/Exception/TimeoutException.ts +10 -0
- package/Types/Exception/TooManyRequestsException.ts +10 -0
- package/Types/Exception/UnableToReachServer.ts +10 -0
- package/Types/Exception/WebsiteRequestException.ts +10 -0
- package/Types/Monitor/CriteriaFilter.ts +60 -2
- package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
- package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +76 -0
- package/Types/Monitor/MonitorMetricType.ts +71 -0
- package/Types/Monitor/MonitorStep.ts +76 -0
- package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
- package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
- package/Types/Monitor/MonitorType.ts +47 -1
- package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
- package/Types/Monitor/SqlConnectionConfig.ts +31 -0
- package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
- package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
- package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
- package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
- package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
- package/Types/Permission.ts +90 -0
- package/Types/Probe/ProbeMonitorResponse.ts +16 -0
- package/Types/Telemetry/ErrorClass.ts +274 -0
- package/Types/Telemetry/UnitOfWork.ts +59 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
- package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
- package/UI/Components/Modal/Modal.tsx +2 -8
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
- package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
- package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
- package/UI/Components/SideMenu/SideMenu.tsx +123 -5
- package/UI/Components/SideMenu/SideMenuItem.tsx +76 -84
- package/UI/Components/SideMenu/SideMenuSection.tsx +55 -23
- package/UI/Components/SideOver/SideOver.tsx +21 -20
- package/UI/Utils/PageScrollLock.ts +79 -3
- package/UI/Utils/PermissionGate.ts +61 -0
- package/UI/Utils/SensitiveUrlToken.ts +112 -0
- package/UI/Utils/TestLLMProvider.ts +11 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
- package/Utils/Monitor/MonitorMetricType.ts +153 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +23 -3
- package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
- package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
- package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
- package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
- package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
- package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
- package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
- package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
- package/build/dist/Models/AnalyticsModels/Span.js +14 -0
- package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +59 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +10 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +75 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js +713 -0
- package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +180 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
- package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
- package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
- package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js +363 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
- package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +108 -13
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +12 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.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/Infrastructure/QueueWorker.js +33 -5
- package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
- package/build/dist/Server/Middleware/BearerTokenAuthorization.js +12 -0
- package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
- package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +11 -0
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AIBillingService.js +70 -16
- package/build/dist/Server/Services/AIBillingService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js +167 -0
- package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.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/MonitorService.js +119 -21
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
- package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
- package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
- package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +10 -9
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
- package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
- package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
- package/build/dist/Server/Services/NotificationService.js +80 -17
- package/build/dist/Server/Services/NotificationService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +66 -30
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +92 -2
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js +76 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
- package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js +46 -20
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +90 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
- package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
- package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
- package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js +59 -0
- package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +2 -1
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +91 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +691 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
- package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
- package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/LogRedaction.js +8 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
- package/build/dist/Server/Utils/Logger.js +63 -1
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js +141 -0
- package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +51 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +37 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
- package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +32 -0
- package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
- package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
- package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js +30 -17
- package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
- package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
- package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
- package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
- package/build/dist/Server/Utils/OutboundUserAgent.js.map +1 -0
- package/build/dist/Server/Utils/StartServer.js +38 -14
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +28 -8
- package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
- package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js +29 -0
- package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry.js +162 -46
- package/build/dist/Server/Utils/Telemetry.js.map +1 -1
- package/build/dist/Types/AI/ExceptionAIClassification.js +10 -24
- package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
- package/build/dist/Types/Exception/ApiException.js +9 -0
- package/build/dist/Types/Exception/ApiException.js.map +1 -1
- package/build/dist/Types/Exception/BadDataException.js +10 -0
- package/build/dist/Types/Exception/BadDataException.js.map +1 -1
- package/build/dist/Types/Exception/BadRequestException.js +10 -0
- package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
- package/build/dist/Types/Exception/Exception.js +56 -0
- package/build/dist/Types/Exception/Exception.js.map +1 -1
- package/build/dist/Types/Exception/ForbiddenException.js +9 -0
- package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
- package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
- package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
- package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
- package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
- package/build/dist/Types/Exception/NotFoundException.js +10 -0
- package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
- package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
- package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
- package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
- package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
- package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
- package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
- package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
- package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
- package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
- package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
- package/build/dist/Types/Exception/TimeoutException.js +9 -0
- package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
- package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
- package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
- package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
- package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
- package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
- package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +45 -2
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
- package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
- package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +70 -0
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
- package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +54 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
- package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
- package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +45 -1
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
- package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
- package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
- package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
- package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
- package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
- package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
- package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js.map +1 -0
- package/build/dist/Types/Permission.js +80 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
- package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
- package/build/dist/Types/Telemetry/UnitOfWork.js +59 -0
- package/build/dist/Types/Telemetry/UnitOfWork.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +2 -7
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +3 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +2 -7
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +39 -0
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
- package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
- package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
- package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +67 -5
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js +49 -53
- package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js +25 -7
- package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Utils/PageScrollLock.js +31 -3
- package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
- package/build/dist/UI/Utils/PermissionGate.js +42 -1
- package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
- package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
- package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -0
- package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
- package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +109 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +8 -3
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
- package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
- package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
- package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
- package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
- package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
- package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
- package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
- package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
- package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
import AIBillingService from "../../../Server/Services/AIBillingService";
|
|
2
|
+
import BillingService from "../../../Server/Services/BillingService";
|
|
3
|
+
import NotificationService from "../../../Server/Services/NotificationService";
|
|
4
|
+
import ProjectService from "../../../Server/Services/ProjectService";
|
|
5
|
+
import GlobalCache from "../../../Server/Infrastructure/GlobalCache";
|
|
6
|
+
import DatabaseNotConnectedException from "../../../Types/Exception/DatabaseNotConnectedException";
|
|
7
|
+
import logger from "../../../Server/Utils/Logger";
|
|
8
|
+
import Project from "../../../Models/DatabaseModels/Project";
|
|
9
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import Path from "path";
|
|
12
|
+
import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* WHAT BREAKS IN PRODUCTION IF THIS REGRESSES.
|
|
16
|
+
*
|
|
17
|
+
* NotificationService.rechargeIfBalanceIsLow is called INLINE on every SMS,
|
|
18
|
+
* call, WhatsApp and Telegram notification attempt (SmsService.ts:282,
|
|
19
|
+
* CallService.ts:299, WhatsAppService.ts:180, TelegramService.ts:168), and
|
|
20
|
+
* AIBillingService is the same shape for AI credits. So anything these two
|
|
21
|
+
* rechargeBalance methods mail is multiplied by the paging rate of the very
|
|
22
|
+
* incident the owner is already being paged about. Four separate defects lived
|
|
23
|
+
* here, and each one turns a single billing condition into a per-attempt mail
|
|
24
|
+
* storm:
|
|
25
|
+
*
|
|
26
|
+
* 1. The SUCCESS mail had no guard flag at all. A project auto-recharging
|
|
27
|
+
* through an outage mailed every owner once per recharge, and the same
|
|
28
|
+
* update reset lowCallAndSMSBalanceNotificationSentToOwners and
|
|
29
|
+
* notEnabledSmsOrCallNotificationSentToOwners to false, re-arming two
|
|
30
|
+
* MORE owner emails. It is now suppressed for AUTO-recharge only. The
|
|
31
|
+
* manual "Recharge" button keeps it, because Project.sendInvoicesByEmail
|
|
32
|
+
* defaults to false, so the Stripe invoice is filed rather than sent and
|
|
33
|
+
* the Slack hook is an operator webhook most installs never configure -
|
|
34
|
+
* delete it there and a person who charged their own card is told
|
|
35
|
+
* nothing. That split is the first two tests in each describe.
|
|
36
|
+
*
|
|
37
|
+
* 2. The catch block WROTE failedCallAndSMSBalanceChargeNotificationSentToOwners
|
|
38
|
+
* = true and then mailed without ever reading it - unlike its correctly
|
|
39
|
+
* guarded sibling twenty lines above. A declined card therefore mailed
|
|
40
|
+
* every owner once per paging attempt, forever.
|
|
41
|
+
*
|
|
42
|
+
* 3. The obvious fix for 2 - gate the catch on that same boolean - swaps a
|
|
43
|
+
* storm for something worse, and the suite pins that it was NOT done. The
|
|
44
|
+
* boolean is cleared only by a SUCCESSFUL recharge, so: no card -> mail
|
|
45
|
+
* once and latch -> the owner adds a card -> the card is declined -> the
|
|
46
|
+
* recharge can never succeed -> the latch never clears -> nobody is ever
|
|
47
|
+
* told the new card failed and paging silently stops. The guard is a 24h
|
|
48
|
+
* WINDOW instead (BillingFailureNoticeThrottle), and it fails OPEN.
|
|
49
|
+
*
|
|
50
|
+
* 4. Guarding the catch at all exposes a double-send that was invisible
|
|
51
|
+
* before it: the no-payment-method branch mails and then THROWS, and that
|
|
52
|
+
* throw lands in this method's own catch. Without the local
|
|
53
|
+
* already-told-them flag, a first no-payment-method failure sends TWO
|
|
54
|
+
* identical "ACTION REQUIRED" emails. That is the assertion below that
|
|
55
|
+
* only makes sense once you trace the throw.
|
|
56
|
+
*
|
|
57
|
+
* 5. AIBillingService had bugs 1-4 byte-for-byte.
|
|
58
|
+
*
|
|
59
|
+
* Both services are gated on IsBillingEnabled, so these are CLOUD-ONLY paths.
|
|
60
|
+
* The last describe is a ratchet on the SIBLING owner emails in the four
|
|
61
|
+
* notification services: those are already guarded by their own project
|
|
62
|
+
* booleans, they are deliberately out of scope, and a future edit that
|
|
63
|
+
* un-guards one of them would reintroduce exactly the storm this suite exists
|
|
64
|
+
* to prevent.
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* AIBillingService.rechargeBalance throws "Billing is not enabled" before it
|
|
69
|
+
* does anything else, and BILLING_ENABLED is not set when jest runs a single
|
|
70
|
+
* suite directly. Mocking the tiny BillingConfig module (rather than
|
|
71
|
+
* EnvironmentConfig, which reads it) is the precedent set by
|
|
72
|
+
* Tests/Server/TestingUtils/Services/BillingServiceHelper.ts, and it makes the
|
|
73
|
+
* suite deterministic no matter what the runner exports.
|
|
74
|
+
*/
|
|
75
|
+
jest.mock("../../../Server/BillingConfig", () => {
|
|
76
|
+
return {
|
|
77
|
+
__esModule: true,
|
|
78
|
+
default: {
|
|
79
|
+
IsBillingEnabled: true,
|
|
80
|
+
BillingPublicKey: "pk_test_billing_recharge_guards",
|
|
81
|
+
BillingPrivateKey: "sk_test_billing_recharge_guards",
|
|
82
|
+
BillingWebhookSecret: "whsec_test_billing_recharge_guards",
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const PROJECT_ID: ObjectID = new ObjectID(
|
|
88
|
+
"11111111-1111-4111-8111-111111111111",
|
|
89
|
+
);
|
|
90
|
+
const PROJECT_NAME: string = "Acme Production";
|
|
91
|
+
const CUSTOMER_ID: string = "cus_test_recharge_guards";
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
* sendBalanceRefillSlackNotification is private on both services. The suite
|
|
95
|
+
* has to assert it still fires after the success mail was deleted, so it is
|
|
96
|
+
* reached through a structural type rather than through the class.
|
|
97
|
+
*/
|
|
98
|
+
interface SlackRefillNotifier {
|
|
99
|
+
sendBalanceRefillSlackNotification: (data: {
|
|
100
|
+
project: Project;
|
|
101
|
+
amountInUSD: number;
|
|
102
|
+
currentBalanceInUSD: number;
|
|
103
|
+
}) => Promise<void>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
type MakeSmsProjectFunction = (data: {
|
|
107
|
+
failedFlagAlreadySet: boolean;
|
|
108
|
+
}) => Project;
|
|
109
|
+
|
|
110
|
+
const makeSmsProject: MakeSmsProjectFunction = (data: {
|
|
111
|
+
failedFlagAlreadySet: boolean;
|
|
112
|
+
}): Project => {
|
|
113
|
+
const project: Project = new Project();
|
|
114
|
+
project.id = PROJECT_ID;
|
|
115
|
+
project.name = PROJECT_NAME;
|
|
116
|
+
project.paymentProviderCustomerId = CUSTOMER_ID;
|
|
117
|
+
project.smsOrCallCurrentBalanceInUSDCents = 100;
|
|
118
|
+
project.sendInvoicesByEmail = false;
|
|
119
|
+
project.failedCallAndSMSBalanceChargeNotificationSentToOwners =
|
|
120
|
+
data.failedFlagAlreadySet;
|
|
121
|
+
|
|
122
|
+
return project;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
type MakeAiProjectFunction = (data: {
|
|
126
|
+
failedFlagAlreadySet: boolean;
|
|
127
|
+
}) => Project;
|
|
128
|
+
|
|
129
|
+
const makeAiProject: MakeAiProjectFunction = (data: {
|
|
130
|
+
failedFlagAlreadySet: boolean;
|
|
131
|
+
}): Project => {
|
|
132
|
+
const project: Project = new Project();
|
|
133
|
+
project.id = PROJECT_ID;
|
|
134
|
+
project.name = PROJECT_NAME;
|
|
135
|
+
project.paymentProviderCustomerId = CUSTOMER_ID;
|
|
136
|
+
project.aiCurrentBalanceInUSDCents = 100;
|
|
137
|
+
project.sendInvoicesByEmail = false;
|
|
138
|
+
project.failedAiBalanceChargeNotificationSentToOwners =
|
|
139
|
+
data.failedFlagAlreadySet;
|
|
140
|
+
|
|
141
|
+
return project;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
let findOneByIdSpy: jest.SpyInstance;
|
|
145
|
+
let updateOneByIdSpy: jest.SpyInstance;
|
|
146
|
+
let sendEmailSpy: jest.SpyInstance;
|
|
147
|
+
let hasPaymentMethodsSpy: jest.SpyInstance;
|
|
148
|
+
let generateInvoiceSpy: jest.SpyInstance;
|
|
149
|
+
let smsSlackSpy: jest.SpyInstance;
|
|
150
|
+
let aiSlackSpy: jest.SpyInstance;
|
|
151
|
+
let claimWindowSpy: jest.SpyInstance;
|
|
152
|
+
|
|
153
|
+
/* The `data` object of the nth ProjectService.updateOneById call. */
|
|
154
|
+
type GetUpdateDataFunction = (index: number) => Record<string, unknown>;
|
|
155
|
+
|
|
156
|
+
const getUpdateData: GetUpdateDataFunction = (
|
|
157
|
+
index: number,
|
|
158
|
+
): Record<string, unknown> => {
|
|
159
|
+
const call: Array<unknown> = updateOneByIdSpy.mock.calls[
|
|
160
|
+
index
|
|
161
|
+
] as Array<unknown>;
|
|
162
|
+
const argument: Record<string, unknown> = call[0] as Record<string, unknown>;
|
|
163
|
+
|
|
164
|
+
return argument["data"] as Record<string, unknown>;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/* The subject line of the nth owner email the service asked to send. */
|
|
168
|
+
type GetSentSubjectFunction = (index: number) => string;
|
|
169
|
+
|
|
170
|
+
const getSentSubject: GetSentSubjectFunction = (index: number): string => {
|
|
171
|
+
const call: Array<unknown> = sendEmailSpy.mock.calls[index] as Array<unknown>;
|
|
172
|
+
|
|
173
|
+
return call[1] as string;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
beforeEach(() => {
|
|
177
|
+
findOneByIdSpy = jest
|
|
178
|
+
.spyOn(ProjectService, "findOneById")
|
|
179
|
+
.mockResolvedValue(null);
|
|
180
|
+
|
|
181
|
+
updateOneByIdSpy = jest
|
|
182
|
+
.spyOn(ProjectService, "updateOneById")
|
|
183
|
+
.mockResolvedValue(1);
|
|
184
|
+
|
|
185
|
+
sendEmailSpy = jest
|
|
186
|
+
.spyOn(ProjectService, "sendEmailToProjectOwners")
|
|
187
|
+
.mockResolvedValue(undefined);
|
|
188
|
+
|
|
189
|
+
hasPaymentMethodsSpy = jest
|
|
190
|
+
.spyOn(BillingService, "hasPaymentMethods")
|
|
191
|
+
.mockResolvedValue(true);
|
|
192
|
+
|
|
193
|
+
generateInvoiceSpy = jest
|
|
194
|
+
.spyOn(BillingService, "generateInvoiceAndChargeCustomer")
|
|
195
|
+
.mockResolvedValue(undefined);
|
|
196
|
+
|
|
197
|
+
smsSlackSpy = jest
|
|
198
|
+
.spyOn(
|
|
199
|
+
NotificationService as unknown as SlackRefillNotifier,
|
|
200
|
+
"sendBalanceRefillSlackNotification",
|
|
201
|
+
)
|
|
202
|
+
.mockResolvedValue(undefined);
|
|
203
|
+
|
|
204
|
+
aiSlackSpy = jest
|
|
205
|
+
.spyOn(
|
|
206
|
+
AIBillingService as unknown as SlackRefillNotifier,
|
|
207
|
+
"sendBalanceRefillSlackNotification",
|
|
208
|
+
)
|
|
209
|
+
.mockResolvedValue(undefined);
|
|
210
|
+
|
|
211
|
+
/*
|
|
212
|
+
* True means "this call owns today's window". Redis is not running under
|
|
213
|
+
* jest, so without this the real setStringIfNotExists throws and every test
|
|
214
|
+
* would reach the send through the fail-open catch instead of through the
|
|
215
|
+
* behaviour it means to pin.
|
|
216
|
+
*/
|
|
217
|
+
claimWindowSpy = jest
|
|
218
|
+
.spyOn(GlobalCache, "setStringIfNotExists")
|
|
219
|
+
.mockResolvedValue(true);
|
|
220
|
+
|
|
221
|
+
// The catch blocks log the underlying failure; silenced, not asserted on.
|
|
222
|
+
jest.spyOn(logger, "error").mockImplementation((): void => {});
|
|
223
|
+
jest.spyOn(logger, "warn").mockImplementation((): void => {});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
afterEach(() => {
|
|
227
|
+
jest.restoreAllMocks();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe("NotificationService.rechargeBalance - SMS and call owner emails", () => {
|
|
231
|
+
test("a successful AUTO recharge mails project owners zero times", async () => {
|
|
232
|
+
findOneByIdSpy.mockResolvedValue(
|
|
233
|
+
makeSmsProject({ failedFlagAlreadySet: false }),
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
const balance: number = await NotificationService.rechargeBalance(
|
|
237
|
+
PROJECT_ID,
|
|
238
|
+
20,
|
|
239
|
+
{ sendOwnerConfirmationEmail: false },
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
expect(balance).toBe(2100);
|
|
243
|
+
expect(generateInvoiceSpy).toHaveBeenCalledTimes(1);
|
|
244
|
+
|
|
245
|
+
/*
|
|
246
|
+
* The whole point. rechargeIfBalanceIsLow runs on every paging attempt, so
|
|
247
|
+
* one mail per successful recharge is one mail per attempt.
|
|
248
|
+
*/
|
|
249
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(0);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
test("the auto-recharge caller is the one that asks for silence", async () => {
|
|
253
|
+
/*
|
|
254
|
+
* Pinning the CALLER, not just the option, because the option defaults to
|
|
255
|
+
* "send" and the whole reduction depends on rechargeIfBalanceIsLow being
|
|
256
|
+
* the place that opts out. Reading the source is the only way to assert it
|
|
257
|
+
* without standing up the four notification services that call it.
|
|
258
|
+
*/
|
|
259
|
+
const source: string = fs.readFileSync(
|
|
260
|
+
Path.resolve(
|
|
261
|
+
__dirname,
|
|
262
|
+
"../../../Server/Services/NotificationService.ts",
|
|
263
|
+
),
|
|
264
|
+
"utf-8",
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
const autoRechargeBody: string = source.slice(
|
|
268
|
+
source.indexOf("public async rechargeIfBalanceIsLow("),
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
expect(autoRechargeBody).toContain("sendOwnerConfirmationEmail: false");
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test("a successful MANUAL recharge still confirms to the owners", async () => {
|
|
275
|
+
findOneByIdSpy.mockResolvedValue(
|
|
276
|
+
makeSmsProject({ failedFlagAlreadySet: false }),
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
/*
|
|
280
|
+
* NotificationAPI's "Recharge" endpoint calls rechargeBalance with no
|
|
281
|
+
* options. Project.sendInvoicesByEmail defaults to false, so the Stripe
|
|
282
|
+
* invoice is filed and not sent, and the Slack hook is empty on most
|
|
283
|
+
* installs - this email is the only thing that tells a person their card
|
|
284
|
+
* was charged.
|
|
285
|
+
*/
|
|
286
|
+
await NotificationService.rechargeBalance(PROJECT_ID, 20);
|
|
287
|
+
|
|
288
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
289
|
+
expect(getSentSubject(0)).toBe(
|
|
290
|
+
"SMS and Call Recharge Successful for project - " + PROJECT_NAME,
|
|
291
|
+
);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test("a successful recharge still resets all three owner-email flags", async () => {
|
|
295
|
+
findOneByIdSpy.mockResolvedValue(
|
|
296
|
+
makeSmsProject({ failedFlagAlreadySet: true }),
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
await NotificationService.rechargeBalance(PROJECT_ID, 20);
|
|
300
|
+
|
|
301
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(1);
|
|
302
|
+
|
|
303
|
+
const data: Record<string, unknown> = getUpdateData(0);
|
|
304
|
+
|
|
305
|
+
expect(data["smsOrCallCurrentBalanceInUSDCents"]).toBe(2100);
|
|
306
|
+
|
|
307
|
+
/*
|
|
308
|
+
* These resets are correct and deliberately untouched: with the balance
|
|
309
|
+
* topped up, the three conditions that armed those mails are gone, so the
|
|
310
|
+
* next genuine failure must be allowed to mail once.
|
|
311
|
+
*/
|
|
312
|
+
expect(data["failedCallAndSMSBalanceChargeNotificationSentToOwners"]).toBe(
|
|
313
|
+
false,
|
|
314
|
+
);
|
|
315
|
+
expect(data["lowCallAndSMSBalanceNotificationSentToOwners"]).toBe(false);
|
|
316
|
+
expect(data["notEnabledSmsOrCallNotificationSentToOwners"]).toBe(false);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
test("a successful recharge still fires the Slack balance-refill notification", async () => {
|
|
320
|
+
findOneByIdSpy.mockResolvedValue(
|
|
321
|
+
makeSmsProject({ failedFlagAlreadySet: false }),
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
await NotificationService.rechargeBalance(PROJECT_ID, 20);
|
|
325
|
+
|
|
326
|
+
expect(smsSlackSpy).toHaveBeenCalledTimes(1);
|
|
327
|
+
expect(smsSlackSpy).toHaveBeenCalledWith(
|
|
328
|
+
expect.objectContaining({
|
|
329
|
+
amountInUSD: 20,
|
|
330
|
+
currentBalanceInUSD: 21,
|
|
331
|
+
}),
|
|
332
|
+
);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test("a first recharge failure mails owners exactly once and sets the flag", async () => {
|
|
336
|
+
findOneByIdSpy.mockResolvedValue(
|
|
337
|
+
makeSmsProject({ failedFlagAlreadySet: false }),
|
|
338
|
+
);
|
|
339
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
340
|
+
|
|
341
|
+
await expect(
|
|
342
|
+
NotificationService.rechargeBalance(PROJECT_ID, 20),
|
|
343
|
+
).rejects.toThrow("card_declined");
|
|
344
|
+
|
|
345
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
346
|
+
expect(getSentSubject(0)).toBe(
|
|
347
|
+
"ACTION REQUIRED: SMS and Call Recharge Failed for project - " +
|
|
348
|
+
PROJECT_NAME,
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(1);
|
|
352
|
+
expect(
|
|
353
|
+
getUpdateData(0)["failedCallAndSMSBalanceChargeNotificationSentToOwners"],
|
|
354
|
+
).toBe(true);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test("a repeat recharge failure inside the 24h window mails owners zero times", async () => {
|
|
358
|
+
findOneByIdSpy.mockResolvedValue(
|
|
359
|
+
makeSmsProject({ failedFlagAlreadySet: true }),
|
|
360
|
+
);
|
|
361
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
362
|
+
|
|
363
|
+
// Somebody already holds today's window.
|
|
364
|
+
claimWindowSpy.mockResolvedValue(false);
|
|
365
|
+
|
|
366
|
+
await expect(
|
|
367
|
+
NotificationService.rechargeBalance(PROJECT_ID, 20),
|
|
368
|
+
).rejects.toThrow("card_declined");
|
|
369
|
+
|
|
370
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(0);
|
|
371
|
+
|
|
372
|
+
/*
|
|
373
|
+
* The flag write lives inside the same guard as the send. Re-writing true
|
|
374
|
+
* over true is a wasted round trip on a path that runs once per paging
|
|
375
|
+
* attempt, so the guard covers both.
|
|
376
|
+
*/
|
|
377
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(0);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
test("a NEW failure after the window expires still reaches the owners, even with the flag latched", async () => {
|
|
381
|
+
/*
|
|
382
|
+
* THE REGRESSION GUARD FOR PERMANENT SILENCE, and the reason the guard is
|
|
383
|
+
* a window and not the project boolean.
|
|
384
|
+
*
|
|
385
|
+
* Sequence this stands in for: the project had no payment method, so the
|
|
386
|
+
* boolean was set true and never cleared (it clears only on a SUCCESSFUL
|
|
387
|
+
* recharge). The owner then adds a card and the card is declined. If the
|
|
388
|
+
* catch were gated on the boolean, that owner would never be told - and
|
|
389
|
+
* because the recharge can never succeed, never told again either. SMS and
|
|
390
|
+
* voice paging would stop with no notice at all.
|
|
391
|
+
*/
|
|
392
|
+
findOneByIdSpy.mockResolvedValue(
|
|
393
|
+
makeSmsProject({ failedFlagAlreadySet: true }),
|
|
394
|
+
);
|
|
395
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
396
|
+
|
|
397
|
+
// Yesterday's window has expired, so this call claims a fresh one.
|
|
398
|
+
claimWindowSpy.mockResolvedValue(true);
|
|
399
|
+
|
|
400
|
+
await expect(
|
|
401
|
+
NotificationService.rechargeBalance(PROJECT_ID, 20),
|
|
402
|
+
).rejects.toThrow("card_declined");
|
|
403
|
+
|
|
404
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
405
|
+
expect(getSentSubject(0)).toBe(
|
|
406
|
+
"ACTION REQUIRED: SMS and Call Recharge Failed for project - " +
|
|
407
|
+
PROJECT_NAME,
|
|
408
|
+
);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
test("the failure notice is sent when the shared cache is unreachable", async () => {
|
|
412
|
+
/*
|
|
413
|
+
* FAILS OPEN. A Redis blip must not be able to silence "we could not top
|
|
414
|
+
* your balance up", because the consequence of that going unheard is that
|
|
415
|
+
* nobody can be paged. One duplicated email is the cheaper mistake.
|
|
416
|
+
*/
|
|
417
|
+
findOneByIdSpy.mockResolvedValue(
|
|
418
|
+
makeSmsProject({ failedFlagAlreadySet: true }),
|
|
419
|
+
);
|
|
420
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
421
|
+
claimWindowSpy.mockRejectedValue(
|
|
422
|
+
new DatabaseNotConnectedException("Cache is not connected"),
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
await expect(
|
|
426
|
+
NotificationService.rechargeBalance(PROJECT_ID, 20),
|
|
427
|
+
).rejects.toThrow("card_declined");
|
|
428
|
+
|
|
429
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
test("the window is claimed per project and per kind of failure", async () => {
|
|
433
|
+
findOneByIdSpy.mockResolvedValue(
|
|
434
|
+
makeSmsProject({ failedFlagAlreadySet: false }),
|
|
435
|
+
);
|
|
436
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
437
|
+
|
|
438
|
+
await expect(
|
|
439
|
+
NotificationService.rechargeBalance(PROJECT_ID, 20),
|
|
440
|
+
).rejects.toThrow("card_declined");
|
|
441
|
+
|
|
442
|
+
expect(claimWindowSpy).toHaveBeenCalledTimes(1);
|
|
443
|
+
|
|
444
|
+
const call: Array<unknown> = claimWindowSpy.mock.calls[0] as Array<unknown>;
|
|
445
|
+
|
|
446
|
+
expect(call[0]).toBe("billing-failure-notice");
|
|
447
|
+
expect(call[1]).toBe(
|
|
448
|
+
`${PROJECT_ID.toString()}-sms-and-call-recharge-failed`,
|
|
449
|
+
);
|
|
450
|
+
expect(call[3]).toEqual({ expiresInSeconds: 86400 });
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
test("the no-payment-method path mails owners exactly once, not twice", async () => {
|
|
454
|
+
findOneByIdSpy.mockResolvedValue(
|
|
455
|
+
makeSmsProject({ failedFlagAlreadySet: false }),
|
|
456
|
+
);
|
|
457
|
+
hasPaymentMethodsSpy.mockResolvedValue(false);
|
|
458
|
+
|
|
459
|
+
await expect(
|
|
460
|
+
NotificationService.rechargeBalance(PROJECT_ID, 20),
|
|
461
|
+
).rejects.toThrow("No payment methods found for the project");
|
|
462
|
+
|
|
463
|
+
/*
|
|
464
|
+
* The regression guard for the throw falling into this method's own catch.
|
|
465
|
+
* Before the in-memory flag was set in the no-payment-method branch, the
|
|
466
|
+
* catch's newly added guard still read false and sent a second copy.
|
|
467
|
+
*/
|
|
468
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
469
|
+
expect(getSentSubject(0)).toBe(
|
|
470
|
+
"ACTION REQUIRED: SMS and Call Recharge Failed for project - " +
|
|
471
|
+
PROJECT_NAME,
|
|
472
|
+
);
|
|
473
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(1);
|
|
474
|
+
expect(generateInvoiceSpy).toHaveBeenCalledTimes(0);
|
|
475
|
+
|
|
476
|
+
/*
|
|
477
|
+
* Exactly ONE window claim, taken by the branch. The catch is suppressed
|
|
478
|
+
* by the local already-told-them flag rather than by a second claim, so
|
|
479
|
+
* the throw cannot burn a second day's window on its way past.
|
|
480
|
+
*/
|
|
481
|
+
expect(claimWindowSpy).toHaveBeenCalledTimes(1);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
test("a repeat no-payment-method failure inside the window mails owners zero times", async () => {
|
|
485
|
+
findOneByIdSpy.mockResolvedValue(
|
|
486
|
+
makeSmsProject({ failedFlagAlreadySet: true }),
|
|
487
|
+
);
|
|
488
|
+
hasPaymentMethodsSpy.mockResolvedValue(false);
|
|
489
|
+
claimWindowSpy.mockResolvedValue(false);
|
|
490
|
+
|
|
491
|
+
await expect(
|
|
492
|
+
NotificationService.rechargeBalance(PROJECT_ID, 20),
|
|
493
|
+
).rejects.toThrow("No payment methods found for the project");
|
|
494
|
+
|
|
495
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(0);
|
|
496
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(0);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
test("a still-missing payment method is reported again the next day", async () => {
|
|
500
|
+
/*
|
|
501
|
+
* The no-payment-method branch is on a window too, not on the boolean.
|
|
502
|
+
* Latching it would mean a project that never manages a successful
|
|
503
|
+
* recharge - which is every project with no card - is told exactly once,
|
|
504
|
+
* ever, that nobody can be paged for them.
|
|
505
|
+
*/
|
|
506
|
+
findOneByIdSpy.mockResolvedValue(
|
|
507
|
+
makeSmsProject({ failedFlagAlreadySet: true }),
|
|
508
|
+
);
|
|
509
|
+
hasPaymentMethodsSpy.mockResolvedValue(false);
|
|
510
|
+
claimWindowSpy.mockResolvedValue(true);
|
|
511
|
+
|
|
512
|
+
await expect(
|
|
513
|
+
NotificationService.rechargeBalance(PROJECT_ID, 20),
|
|
514
|
+
).rejects.toThrow("No payment methods found for the project");
|
|
515
|
+
|
|
516
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
517
|
+
expect(getSentSubject(0)).toBe(
|
|
518
|
+
"ACTION REQUIRED: SMS and Call Recharge Failed for project - " +
|
|
519
|
+
PROJECT_NAME,
|
|
520
|
+
);
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
describe("AIBillingService.rechargeBalance - AI credit owner emails", () => {
|
|
525
|
+
test("a successful AUTO recharge mails project owners zero times", async () => {
|
|
526
|
+
findOneByIdSpy.mockResolvedValue(
|
|
527
|
+
makeAiProject({ failedFlagAlreadySet: false }),
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
const balance: number = await AIBillingService.rechargeBalance(
|
|
531
|
+
PROJECT_ID,
|
|
532
|
+
20,
|
|
533
|
+
{ sendOwnerConfirmationEmail: false },
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
expect(balance).toBe(2100);
|
|
537
|
+
expect(generateInvoiceSpy).toHaveBeenCalledTimes(1);
|
|
538
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(0);
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
test("the auto-recharge caller is the one that asks for silence", () => {
|
|
542
|
+
const source: string = fs.readFileSync(
|
|
543
|
+
Path.resolve(__dirname, "../../../Server/Services/AIBillingService.ts"),
|
|
544
|
+
"utf-8",
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
const autoRechargeBody: string = source.slice(
|
|
548
|
+
source.indexOf("public async rechargeIfBalanceIsLow("),
|
|
549
|
+
);
|
|
550
|
+
|
|
551
|
+
expect(autoRechargeBody).toContain("sendOwnerConfirmationEmail: false");
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
test("a successful MANUAL recharge still confirms to the owners", async () => {
|
|
555
|
+
findOneByIdSpy.mockResolvedValue(
|
|
556
|
+
makeAiProject({ failedFlagAlreadySet: false }),
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
await AIBillingService.rechargeBalance(PROJECT_ID, 20);
|
|
560
|
+
|
|
561
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
562
|
+
expect(getSentSubject(0)).toBe(
|
|
563
|
+
"AI Balance Recharge Successful for project - " + PROJECT_NAME,
|
|
564
|
+
);
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
test("a successful recharge still resets all three owner-email flags and fires Slack", async () => {
|
|
568
|
+
findOneByIdSpy.mockResolvedValue(
|
|
569
|
+
makeAiProject({ failedFlagAlreadySet: true }),
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
await AIBillingService.rechargeBalance(PROJECT_ID, 20);
|
|
573
|
+
|
|
574
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(1);
|
|
575
|
+
|
|
576
|
+
const data: Record<string, unknown> = getUpdateData(0);
|
|
577
|
+
|
|
578
|
+
expect(data["aiCurrentBalanceInUSDCents"]).toBe(2100);
|
|
579
|
+
expect(data["failedAiBalanceChargeNotificationSentToOwners"]).toBe(false);
|
|
580
|
+
expect(data["lowAiBalanceNotificationSentToOwners"]).toBe(false);
|
|
581
|
+
expect(data["notEnabledAiNotificationSentToOwners"]).toBe(false);
|
|
582
|
+
|
|
583
|
+
expect(aiSlackSpy).toHaveBeenCalledTimes(1);
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
test("a first recharge failure mails owners exactly once and sets the flag", async () => {
|
|
587
|
+
findOneByIdSpy.mockResolvedValue(
|
|
588
|
+
makeAiProject({ failedFlagAlreadySet: false }),
|
|
589
|
+
);
|
|
590
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
591
|
+
|
|
592
|
+
await expect(
|
|
593
|
+
AIBillingService.rechargeBalance(PROJECT_ID, 20),
|
|
594
|
+
).rejects.toThrow("card_declined");
|
|
595
|
+
|
|
596
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
597
|
+
expect(getSentSubject(0)).toBe(
|
|
598
|
+
"ACTION REQUIRED: AI Balance Recharge Failed for project - " +
|
|
599
|
+
PROJECT_NAME,
|
|
600
|
+
);
|
|
601
|
+
|
|
602
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(1);
|
|
603
|
+
expect(
|
|
604
|
+
getUpdateData(0)["failedAiBalanceChargeNotificationSentToOwners"],
|
|
605
|
+
).toBe(true);
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
test("a repeat recharge failure inside the 24h window mails owners zero times", async () => {
|
|
609
|
+
findOneByIdSpy.mockResolvedValue(
|
|
610
|
+
makeAiProject({ failedFlagAlreadySet: true }),
|
|
611
|
+
);
|
|
612
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
613
|
+
claimWindowSpy.mockResolvedValue(false);
|
|
614
|
+
|
|
615
|
+
await expect(
|
|
616
|
+
AIBillingService.rechargeBalance(PROJECT_ID, 20),
|
|
617
|
+
).rejects.toThrow("card_declined");
|
|
618
|
+
|
|
619
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(0);
|
|
620
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(0);
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
test("a NEW failure after the window expires still reaches the owners, even with the flag latched", async () => {
|
|
624
|
+
// The permanent-silence guard. See the SMS twin for the full sequence.
|
|
625
|
+
findOneByIdSpy.mockResolvedValue(
|
|
626
|
+
makeAiProject({ failedFlagAlreadySet: true }),
|
|
627
|
+
);
|
|
628
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
629
|
+
claimWindowSpy.mockResolvedValue(true);
|
|
630
|
+
|
|
631
|
+
await expect(
|
|
632
|
+
AIBillingService.rechargeBalance(PROJECT_ID, 20),
|
|
633
|
+
).rejects.toThrow("card_declined");
|
|
634
|
+
|
|
635
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
636
|
+
expect(getSentSubject(0)).toBe(
|
|
637
|
+
"ACTION REQUIRED: AI Balance Recharge Failed for project - " +
|
|
638
|
+
PROJECT_NAME,
|
|
639
|
+
);
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
test("the failure notice is sent when the shared cache is unreachable", async () => {
|
|
643
|
+
findOneByIdSpy.mockResolvedValue(
|
|
644
|
+
makeAiProject({ failedFlagAlreadySet: true }),
|
|
645
|
+
);
|
|
646
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
647
|
+
claimWindowSpy.mockRejectedValue(
|
|
648
|
+
new DatabaseNotConnectedException("Cache is not connected"),
|
|
649
|
+
);
|
|
650
|
+
|
|
651
|
+
await expect(
|
|
652
|
+
AIBillingService.rechargeBalance(PROJECT_ID, 20),
|
|
653
|
+
).rejects.toThrow("card_declined");
|
|
654
|
+
|
|
655
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
test("AI credits claim a different window from SMS and call", async () => {
|
|
659
|
+
findOneByIdSpy.mockResolvedValue(
|
|
660
|
+
makeAiProject({ failedFlagAlreadySet: false }),
|
|
661
|
+
);
|
|
662
|
+
generateInvoiceSpy.mockRejectedValue(new Error("card_declined"));
|
|
663
|
+
|
|
664
|
+
await expect(
|
|
665
|
+
AIBillingService.rechargeBalance(PROJECT_ID, 20),
|
|
666
|
+
).rejects.toThrow("card_declined");
|
|
667
|
+
|
|
668
|
+
const call: Array<unknown> = claimWindowSpy.mock.calls[0] as Array<unknown>;
|
|
669
|
+
|
|
670
|
+
/*
|
|
671
|
+
* Sharing a key with the SMS/call notice would mean a declined card
|
|
672
|
+
* silenced one of the two failures for the rest of the day.
|
|
673
|
+
*/
|
|
674
|
+
expect(call[1]).toBe(`${PROJECT_ID.toString()}-ai-credit-recharge-failed`);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
test("the no-payment-method path mails owners exactly once, not twice", async () => {
|
|
678
|
+
findOneByIdSpy.mockResolvedValue(
|
|
679
|
+
makeAiProject({ failedFlagAlreadySet: false }),
|
|
680
|
+
);
|
|
681
|
+
hasPaymentMethodsSpy.mockResolvedValue(false);
|
|
682
|
+
|
|
683
|
+
await expect(
|
|
684
|
+
AIBillingService.rechargeBalance(PROJECT_ID, 20),
|
|
685
|
+
).rejects.toThrow("No payment methods found for the project");
|
|
686
|
+
|
|
687
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
688
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(1);
|
|
689
|
+
expect(generateInvoiceSpy).toHaveBeenCalledTimes(0);
|
|
690
|
+
expect(claimWindowSpy).toHaveBeenCalledTimes(1);
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
test("a repeat no-payment-method failure inside the window mails owners zero times", async () => {
|
|
694
|
+
findOneByIdSpy.mockResolvedValue(
|
|
695
|
+
makeAiProject({ failedFlagAlreadySet: true }),
|
|
696
|
+
);
|
|
697
|
+
hasPaymentMethodsSpy.mockResolvedValue(false);
|
|
698
|
+
claimWindowSpy.mockResolvedValue(false);
|
|
699
|
+
|
|
700
|
+
await expect(
|
|
701
|
+
AIBillingService.rechargeBalance(PROJECT_ID, 20),
|
|
702
|
+
).rejects.toThrow("No payment methods found for the project");
|
|
703
|
+
|
|
704
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(0);
|
|
705
|
+
expect(updateOneByIdSpy).toHaveBeenCalledTimes(0);
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
test("a still-missing payment method is reported again the next day", async () => {
|
|
709
|
+
findOneByIdSpy.mockResolvedValue(
|
|
710
|
+
makeAiProject({ failedFlagAlreadySet: true }),
|
|
711
|
+
);
|
|
712
|
+
hasPaymentMethodsSpy.mockResolvedValue(false);
|
|
713
|
+
claimWindowSpy.mockResolvedValue(true);
|
|
714
|
+
|
|
715
|
+
await expect(
|
|
716
|
+
AIBillingService.rechargeBalance(PROJECT_ID, 20),
|
|
717
|
+
).rejects.toThrow("No payment methods found for the project");
|
|
718
|
+
|
|
719
|
+
expect(sendEmailSpy).toHaveBeenCalledTimes(1);
|
|
720
|
+
});
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
/*
|
|
724
|
+
* The sibling low-balance and not-enabled owner emails live in the four
|
|
725
|
+
* notification services that call rechargeIfBalanceIsLow. Each is already
|
|
726
|
+
* behind its own project boolean, and none of them was touched. They cannot be
|
|
727
|
+
* exercised from here without importing the whole notification feature set, so
|
|
728
|
+
* this is a source ratchet on the one invariant that matters: EVERY owner
|
|
729
|
+
* email in those files sits behind one of the two flags. If a future edit adds
|
|
730
|
+
* an unguarded sendEmailToProjectOwners - which is exactly how the two bugs
|
|
731
|
+
* above came to exist - the counts stop matching and this fails.
|
|
732
|
+
*/
|
|
733
|
+
describe("sibling low-balance and not-enabled owner emails stay guarded", () => {
|
|
734
|
+
const NOTIFICATION_SERVICES_DIRECTORY: string = Path.resolve(
|
|
735
|
+
__dirname,
|
|
736
|
+
"../../../../App/FeatureSet/Notification/Services",
|
|
737
|
+
);
|
|
738
|
+
|
|
739
|
+
type CountOccurrencesFunction = (source: string, needle: string) => number;
|
|
740
|
+
|
|
741
|
+
const countOccurrences: CountOccurrencesFunction = (
|
|
742
|
+
source: string,
|
|
743
|
+
needle: string,
|
|
744
|
+
): number => {
|
|
745
|
+
return source.split(needle).length - 1;
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
const FILE_NAMES: Array<string> = [
|
|
749
|
+
"SmsService.ts",
|
|
750
|
+
"CallService.ts",
|
|
751
|
+
"WhatsAppService.ts",
|
|
752
|
+
"TelegramService.ts",
|
|
753
|
+
];
|
|
754
|
+
|
|
755
|
+
test.each(FILE_NAMES)(
|
|
756
|
+
"%s guards every owner email behind a project flag",
|
|
757
|
+
(fileName: string) => {
|
|
758
|
+
const source: string = fs.readFileSync(
|
|
759
|
+
Path.join(NOTIFICATION_SERVICES_DIRECTORY, fileName),
|
|
760
|
+
"utf-8",
|
|
761
|
+
);
|
|
762
|
+
|
|
763
|
+
const sends: number = countOccurrences(
|
|
764
|
+
source,
|
|
765
|
+
"await ProjectService.sendEmailToProjectOwners(",
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
const guards: number =
|
|
769
|
+
countOccurrences(
|
|
770
|
+
source,
|
|
771
|
+
"if (!project.lowCallAndSMSBalanceNotificationSentToOwners) {",
|
|
772
|
+
) +
|
|
773
|
+
countOccurrences(
|
|
774
|
+
source,
|
|
775
|
+
"if (!project.notEnabledSmsOrCallNotificationSentToOwners) {",
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
// Every file here has at least one, so a path typo cannot pass as 0 === 0.
|
|
779
|
+
expect(sends).toBeGreaterThan(0);
|
|
780
|
+
expect(guards).toBe(sends);
|
|
781
|
+
},
|
|
782
|
+
);
|
|
783
|
+
});
|