@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.
Files changed (597) hide show
  1. package/Models/AnalyticsModels/Span.ts +14 -0
  2. package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
  3. package/Models/DatabaseModels/Index.ts +10 -0
  4. package/Models/DatabaseModels/Monitor.ts +76 -0
  5. package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
  6. package/Models/DatabaseModels/NetworkDevice.ts +176 -1
  7. package/Models/DatabaseModels/NetworkSite.ts +201 -2
  8. package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
  9. package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
  10. package/Models/DatabaseModels/TelemetryException.ts +119 -0
  11. package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
  12. package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
  13. package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
  14. package/Server/API/EnterpriseLicenseAPI.ts +391 -64
  15. package/Server/API/LlmProviderAPI.ts +137 -22
  16. package/Server/EnvironmentConfig.ts +14 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  24. package/Server/Infrastructure/QueueWorker.ts +38 -8
  25. package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
  26. package/Server/Middleware/ProjectAuthorization.ts +11 -0
  27. package/Server/Middleware/SCIMAuthorization.ts +12 -0
  28. package/Server/Middleware/TelemetryIngest.ts +11 -0
  29. package/Server/Services/AIBillingService.ts +101 -27
  30. package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
  31. package/Server/Services/EnterpriseLicenseService.ts +55 -0
  32. package/Server/Services/Index.ts +10 -0
  33. package/Server/Services/MonitorService.ts +143 -21
  34. package/Server/Services/MonitorStatusTimelineService.ts +150 -8
  35. package/Server/Services/MonitorTemplateService.ts +217 -1
  36. package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
  37. package/Server/Services/NetworkAlertPolicyService.ts +944 -0
  38. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +9 -10
  39. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
  40. package/Server/Services/NetworkDeviceService.ts +1032 -73
  41. package/Server/Services/NetworkSiteService.ts +1502 -129
  42. package/Server/Services/NetworkSiteTypeService.ts +1216 -0
  43. package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
  44. package/Server/Services/NotificationService.ts +118 -28
  45. package/Server/Services/ProjectService.ts +105 -48
  46. package/Server/Services/StatusPagePrivateUserService.ts +103 -3
  47. package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
  48. package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
  49. package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
  50. package/Server/Services/UserNotificationSettingService.ts +62 -25
  51. package/Server/Services/UserService.ts +95 -0
  52. package/Server/Types/Database/QueryHelper.ts +2 -2
  53. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
  54. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
  55. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
  56. package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
  57. package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
  58. package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
  59. package/Server/Utils/DataSource/HttpFetch.ts +9 -2
  60. package/Server/Utils/EmailRollup/EmailRollupConstants.ts +98 -0
  61. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +872 -0
  62. package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
  63. package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
  64. package/Server/Utils/LLM/LLMService.ts +78 -0
  65. package/Server/Utils/LogRedaction.ts +8 -0
  66. package/Server/Utils/Logger.ts +79 -1
  67. package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
  68. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
  69. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
  70. package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
  71. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +49 -0
  72. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
  73. package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
  74. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +43 -0
  75. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
  76. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
  77. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
  78. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
  79. package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
  80. package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
  81. package/Server/Utils/OutboundUserAgent.ts +152 -0
  82. package/Server/Utils/StartServer.ts +51 -19
  83. package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
  84. package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
  85. package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
  86. package/Server/Utils/Telemetry.ts +198 -51
  87. package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
  88. package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +134 -33
  89. package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
  90. package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
  91. package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
  92. package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
  93. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +18 -9
  94. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
  95. package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
  96. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
  97. package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
  98. package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
  99. package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
  100. package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
  101. package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
  102. package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +41 -5
  103. package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
  104. package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
  105. package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
  106. package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
  107. package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
  108. package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
  109. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
  110. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
  111. package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
  112. package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
  113. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
  114. package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
  115. package/Tests/Server/Infrastructure/Postgres/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
  116. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
  117. package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
  118. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
  119. package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
  120. package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
  121. package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
  122. package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
  123. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
  124. package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
  125. package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
  126. package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
  127. package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
  128. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +47 -4
  129. package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
  130. package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
  131. package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
  132. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
  133. package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
  134. package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
  135. package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
  136. package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
  137. package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
  138. package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
  139. package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
  140. package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
  141. package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
  142. package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
  143. package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
  144. package/Tests/Server/Services/UserEmailChangePasswordResetExpiry.test.ts +472 -0
  145. package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
  146. package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
  147. package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
  148. package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +856 -0
  149. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +102 -1
  150. package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
  151. package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
  152. package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
  153. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
  154. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
  155. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -0
  156. package/Tests/Server/Utils/Captcha.test.ts +422 -0
  157. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +96 -2
  158. package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
  159. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
  160. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
  161. package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
  162. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +752 -0
  163. package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
  164. package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
  165. package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
  166. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
  167. package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
  168. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
  169. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
  170. package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
  171. package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
  172. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
  173. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
  174. package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
  175. package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
  176. package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
  177. package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
  178. package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
  179. package/Tests/Server/Utils/Telemetry.test.ts +456 -66
  180. package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
  181. package/Tests/Types/Monitor/MonitorStepDatabaseMonitor.test.ts +243 -0
  182. package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
  183. package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
  184. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
  185. package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
  186. package/Tests/Types/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
  187. package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
  188. package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
  189. package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -0
  190. package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
  191. package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
  192. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +15 -0
  193. package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
  194. package/Tests/UI/Components/SideMenuItem.test.tsx +226 -4
  195. package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
  196. package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -0
  197. package/Tests/UI/Utils/PageScrollLock.test.tsx +377 -0
  198. package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
  199. package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
  200. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
  201. package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
  202. package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
  203. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
  204. package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
  205. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
  206. package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
  207. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
  208. package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
  209. package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
  210. package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
  211. package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
  212. package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
  213. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
  214. package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
  215. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
  216. package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
  217. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
  218. package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -0
  219. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
  220. package/Types/AI/ExceptionAIClassification.ts +10 -24
  221. package/Types/Email/EmailTemplateType.ts +2 -0
  222. package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
  223. package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
  224. package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
  225. package/Types/Exception/ApiException.ts +10 -0
  226. package/Types/Exception/BadDataException.ts +11 -0
  227. package/Types/Exception/BadRequestException.ts +11 -0
  228. package/Types/Exception/Exception.ts +65 -0
  229. package/Types/Exception/ForbiddenException.ts +10 -0
  230. package/Types/Exception/NotAuthenticatedException.ts +10 -0
  231. package/Types/Exception/NotAuthorizedException.ts +10 -0
  232. package/Types/Exception/NotFoundException.ts +11 -0
  233. package/Types/Exception/PayloadTooLargeException.ts +11 -0
  234. package/Types/Exception/PaymentRequiredException.ts +10 -0
  235. package/Types/Exception/ServiceUnavailableException.ts +10 -0
  236. package/Types/Exception/SsoAuthorizationException.ts +10 -0
  237. package/Types/Exception/TenantNotFoundException.ts +11 -0
  238. package/Types/Exception/TimeoutException.ts +10 -0
  239. package/Types/Exception/TooManyRequestsException.ts +10 -0
  240. package/Types/Exception/UnableToReachServer.ts +10 -0
  241. package/Types/Exception/WebsiteRequestException.ts +10 -0
  242. package/Types/Monitor/CriteriaFilter.ts +60 -2
  243. package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
  244. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
  245. package/Types/Monitor/MonitorCriteriaInstance.ts +76 -0
  246. package/Types/Monitor/MonitorMetricType.ts +71 -0
  247. package/Types/Monitor/MonitorStep.ts +76 -0
  248. package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
  249. package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
  250. package/Types/Monitor/MonitorType.ts +47 -1
  251. package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
  252. package/Types/Monitor/SqlConnectionConfig.ts +31 -0
  253. package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
  254. package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
  255. package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
  256. package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
  257. package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
  258. package/Types/Permission.ts +90 -0
  259. package/Types/Probe/ProbeMonitorResponse.ts +16 -0
  260. package/Types/Telemetry/ErrorClass.ts +274 -0
  261. package/Types/Telemetry/UnitOfWork.ts +59 -0
  262. package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
  263. package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
  264. package/UI/Components/Modal/Modal.tsx +2 -8
  265. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
  266. package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
  267. package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
  268. package/UI/Components/SideMenu/SideMenu.tsx +123 -5
  269. package/UI/Components/SideMenu/SideMenuItem.tsx +76 -84
  270. package/UI/Components/SideMenu/SideMenuSection.tsx +55 -23
  271. package/UI/Components/SideOver/SideOver.tsx +21 -20
  272. package/UI/Utils/PageScrollLock.ts +79 -3
  273. package/UI/Utils/PermissionGate.ts +61 -0
  274. package/UI/Utils/SensitiveUrlToken.ts +112 -0
  275. package/UI/Utils/TestLLMProvider.ts +11 -0
  276. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
  277. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
  278. package/Utils/Monitor/MonitorMetricType.ts +153 -1
  279. package/Utils/Monitor/NetworkTopologyUtil.ts +23 -3
  280. package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
  281. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
  282. package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
  283. package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
  284. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
  285. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
  286. package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
  287. package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
  288. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
  289. package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
  290. package/build/dist/Models/AnalyticsModels/Span.js +14 -0
  291. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  292. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +59 -0
  293. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  294. package/build/dist/Models/DatabaseModels/Index.js +10 -0
  295. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  296. package/build/dist/Models/DatabaseModels/Monitor.js +75 -0
  297. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  298. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js +713 -0
  299. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
  300. package/build/dist/Models/DatabaseModels/NetworkDevice.js +180 -1
  301. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  302. package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
  303. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
  304. package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
  305. package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
  306. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
  307. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
  308. package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
  309. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  310. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js +363 -0
  311. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
  312. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
  313. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
  314. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
  315. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
  316. package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
  317. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  318. package/build/dist/Server/API/LlmProviderAPI.js +108 -13
  319. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  320. package/build/dist/Server/EnvironmentConfig.js +12 -0
  321. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  322. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
  323. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
  324. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
  325. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
  326. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
  327. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
  328. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
  329. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
  330. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
  331. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
  332. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
  333. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js.map +1 -0
  334. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  335. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  336. package/build/dist/Server/Infrastructure/QueueWorker.js +33 -5
  337. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  338. package/build/dist/Server/Middleware/BearerTokenAuthorization.js +12 -0
  339. package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
  340. package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
  341. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  342. package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
  343. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
  344. package/build/dist/Server/Middleware/TelemetryIngest.js +11 -0
  345. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  346. package/build/dist/Server/Services/AIBillingService.js +70 -16
  347. package/build/dist/Server/Services/AIBillingService.js.map +1 -1
  348. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js +167 -0
  349. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
  350. package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
  351. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  352. package/build/dist/Server/Services/Index.js +10 -0
  353. package/build/dist/Server/Services/Index.js.map +1 -1
  354. package/build/dist/Server/Services/MonitorService.js +119 -21
  355. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  356. package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
  357. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  358. package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
  359. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  360. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
  361. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
  362. package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
  363. package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
  364. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +10 -9
  365. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  366. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
  367. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  368. package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
  369. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  370. package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
  371. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  372. package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
  373. package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
  374. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
  375. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
  376. package/build/dist/Server/Services/NotificationService.js +80 -17
  377. package/build/dist/Server/Services/NotificationService.js.map +1 -1
  378. package/build/dist/Server/Services/ProjectService.js +66 -30
  379. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  380. package/build/dist/Server/Services/StatusPagePrivateUserService.js +92 -2
  381. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  382. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js +76 -0
  383. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
  384. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
  385. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
  386. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
  387. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
  388. package/build/dist/Server/Services/UserNotificationSettingService.js +46 -20
  389. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  390. package/build/dist/Server/Services/UserService.js +90 -0
  391. package/build/dist/Server/Services/UserService.js.map +1 -1
  392. package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
  393. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  394. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
  395. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  396. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
  397. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  398. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
  399. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  400. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
  401. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
  402. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
  403. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
  404. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js +59 -0
  405. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
  406. package/build/dist/Server/Utils/DataSource/HttpFetch.js +2 -1
  407. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
  408. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +91 -0
  409. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
  410. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +691 -0
  411. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
  412. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
  413. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
  414. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
  415. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
  416. package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
  417. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  418. package/build/dist/Server/Utils/LogRedaction.js +8 -0
  419. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  420. package/build/dist/Server/Utils/Logger.js +63 -1
  421. package/build/dist/Server/Utils/Logger.js.map +1 -1
  422. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js +141 -0
  423. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
  424. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  425. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  426. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +51 -1
  427. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  428. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
  429. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
  430. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +37 -0
  431. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  432. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
  433. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  434. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  435. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  436. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +32 -0
  437. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  438. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
  439. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  440. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
  441. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  442. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
  443. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  444. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
  445. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  446. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js +30 -17
  447. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
  448. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
  449. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
  450. package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
  451. package/build/dist/Server/Utils/OutboundUserAgent.js.map +1 -0
  452. package/build/dist/Server/Utils/StartServer.js +38 -14
  453. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  454. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +28 -8
  455. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  456. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
  457. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js.map +1 -0
  458. package/build/dist/Server/Utils/Telemetry/SpanUtil.js +29 -0
  459. package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
  460. package/build/dist/Server/Utils/Telemetry.js +162 -46
  461. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  462. package/build/dist/Types/AI/ExceptionAIClassification.js +10 -24
  463. package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -1
  464. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  465. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  466. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
  467. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
  468. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
  469. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
  470. package/build/dist/Types/Exception/ApiException.js +9 -0
  471. package/build/dist/Types/Exception/ApiException.js.map +1 -1
  472. package/build/dist/Types/Exception/BadDataException.js +10 -0
  473. package/build/dist/Types/Exception/BadDataException.js.map +1 -1
  474. package/build/dist/Types/Exception/BadRequestException.js +10 -0
  475. package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
  476. package/build/dist/Types/Exception/Exception.js +56 -0
  477. package/build/dist/Types/Exception/Exception.js.map +1 -1
  478. package/build/dist/Types/Exception/ForbiddenException.js +9 -0
  479. package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
  480. package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
  481. package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
  482. package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
  483. package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
  484. package/build/dist/Types/Exception/NotFoundException.js +10 -0
  485. package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
  486. package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
  487. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
  488. package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
  489. package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
  490. package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
  491. package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
  492. package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
  493. package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
  494. package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
  495. package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
  496. package/build/dist/Types/Exception/TimeoutException.js +9 -0
  497. package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
  498. package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
  499. package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
  500. package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
  501. package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
  502. package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
  503. package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
  504. package/build/dist/Types/Monitor/CriteriaFilter.js +45 -2
  505. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  506. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
  507. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
  508. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
  509. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
  510. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +70 -0
  511. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  512. package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
  513. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  514. package/build/dist/Types/Monitor/MonitorStep.js +54 -0
  515. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  516. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
  517. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
  518. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
  519. package/build/dist/Types/Monitor/MonitorType.js +45 -1
  520. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  521. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
  522. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
  523. package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
  524. package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
  525. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
  526. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
  527. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
  528. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
  529. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
  530. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
  531. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
  532. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
  533. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
  534. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js.map +1 -0
  535. package/build/dist/Types/Permission.js +80 -0
  536. package/build/dist/Types/Permission.js.map +1 -1
  537. package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
  538. package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
  539. package/build/dist/Types/Telemetry/UnitOfWork.js +59 -0
  540. package/build/dist/Types/Telemetry/UnitOfWork.js.map +1 -0
  541. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +2 -7
  542. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  543. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +3 -0
  544. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  545. package/build/dist/UI/Components/Modal/Modal.js +2 -7
  546. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  547. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +39 -0
  548. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  549. package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
  550. package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
  551. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
  552. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
  553. package/build/dist/UI/Components/SideMenu/SideMenu.js +67 -5
  554. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  555. package/build/dist/UI/Components/SideMenu/SideMenuItem.js +49 -53
  556. package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
  557. package/build/dist/UI/Components/SideMenu/SideMenuSection.js +25 -7
  558. package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
  559. package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
  560. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  561. package/build/dist/UI/Utils/PageScrollLock.js +31 -3
  562. package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
  563. package/build/dist/UI/Utils/PermissionGate.js +42 -1
  564. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  565. package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
  566. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -0
  567. package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
  568. package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
  569. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
  570. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
  571. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
  572. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  573. package/build/dist/Utils/Monitor/MonitorMetricType.js +109 -1
  574. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  575. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +8 -3
  576. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  577. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
  578. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
  579. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
  580. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  581. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
  582. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
  583. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
  584. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
  585. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
  586. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  587. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
  588. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  589. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
  590. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
  591. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
  592. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
  593. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
  594. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  595. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
  596. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js.map +1 -0
  597. 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
+ });