@oneuptime/common 12.0.32 → 12.0.34

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 (1191) hide show
  1. package/Models/AnalyticsModels/RumSession.ts +117 -1
  2. package/Models/AnalyticsModels/RumSessionChunk.ts +13 -0
  3. package/Models/AnalyticsModels/Span.ts +14 -0
  4. package/Models/DatabaseModels/AlertCustomField.ts +77 -3
  5. package/Models/DatabaseModels/ApiKeyPermission.ts +3 -27
  6. package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
  7. package/Models/DatabaseModels/IncidentCustomField.ts +77 -3
  8. package/Models/DatabaseModels/Index.ts +10 -0
  9. package/Models/DatabaseModels/InventoryItemCustomField.ts +77 -3
  10. package/Models/DatabaseModels/Monitor.ts +76 -0
  11. package/Models/DatabaseModels/MonitorCustomField.ts +77 -3
  12. package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
  13. package/Models/DatabaseModels/NetworkDevice.ts +176 -1
  14. package/Models/DatabaseModels/NetworkSite.ts +201 -2
  15. package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
  16. package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
  17. package/Models/DatabaseModels/OnCallDutyPolicyCustomField.ts +77 -3
  18. package/Models/DatabaseModels/RumApplication.ts +6 -6
  19. package/Models/DatabaseModels/ScheduledMaintenanceCustomField.ts +77 -3
  20. package/Models/DatabaseModels/StatusPageCustomField.ts +77 -3
  21. package/Models/DatabaseModels/TeamCustomField.ts +77 -3
  22. package/Models/DatabaseModels/TeamMember.ts +0 -9
  23. package/Models/DatabaseModels/TeamMemberCustomField.ts +77 -3
  24. package/Models/DatabaseModels/TeamPermission.ts +3 -24
  25. package/Models/DatabaseModels/TelemetryException.ts +119 -0
  26. package/Models/DatabaseModels/TelemetryIngestionKey.ts +260 -0
  27. package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
  28. package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
  29. package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
  30. package/Models/DatabaseModels/UserTelegram.ts +0 -4
  31. package/Scripts/benchmark-fanin-capacity.js +181 -0
  32. package/Server/API/EnterpriseLicenseAPI.ts +391 -64
  33. package/Server/API/LlmProviderAPI.ts +137 -22
  34. package/Server/API/TelemetryAPI.ts +1284 -164
  35. package/Server/API/UserNotificationSettingAPI.ts +55 -0
  36. package/Server/API/UserTelegramAPI.ts +48 -4
  37. package/Server/EnvironmentConfig.ts +49 -2
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
  39. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
  40. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
  41. package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
  42. package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
  43. package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
  44. package/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.ts +91 -0
  45. package/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.ts +67 -0
  46. package/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.ts +139 -0
  47. package/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.ts +121 -0
  48. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
  49. package/Server/Infrastructure/QueueWorker.ts +59 -23
  50. package/Server/Infrastructure/Semaphore.ts +2 -0
  51. package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
  52. package/Server/Middleware/ProjectAuthorization.ts +11 -0
  53. package/Server/Middleware/SCIMAuthorization.ts +12 -0
  54. package/Server/Middleware/TelemetryIngest.ts +464 -7
  55. package/Server/Services/AIBillingService.ts +101 -27
  56. package/Server/Services/AccessTokenService.ts +1 -0
  57. package/Server/Services/AlertCustomFieldService.ts +98 -0
  58. package/Server/Services/AlertService.ts +37 -0
  59. package/Server/Services/ApiKeyPermissionService.ts +461 -29
  60. package/Server/Services/CustomFieldMappingService.ts +879 -0
  61. package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
  62. package/Server/Services/EnterpriseLicenseService.ts +55 -0
  63. package/Server/Services/GlobalConfigService.ts +194 -0
  64. package/Server/Services/IncidentCustomFieldService.ts +98 -0
  65. package/Server/Services/IncidentService.ts +35 -0
  66. package/Server/Services/Index.ts +10 -0
  67. package/Server/Services/MetricService.ts +194 -0
  68. package/Server/Services/MonitorService.ts +175 -21
  69. package/Server/Services/MonitorStatusTimelineService.ts +150 -8
  70. package/Server/Services/MonitorTemplateService.ts +217 -1
  71. package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
  72. package/Server/Services/NetworkAlertPolicyService.ts +944 -0
  73. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +87 -35
  74. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
  75. package/Server/Services/NetworkDeviceService.ts +1032 -73
  76. package/Server/Services/NetworkSiteService.ts +1502 -129
  77. package/Server/Services/NetworkSiteTypeService.ts +1216 -0
  78. package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
  79. package/Server/Services/NotificationService.ts +118 -28
  80. package/Server/Services/ProjectService.ts +127 -48
  81. package/Server/Services/RoutineEmailSettingsService.ts +73 -0
  82. package/Server/Services/RumSessionReplayViewService.ts +104 -24
  83. package/Server/Services/ScheduledMaintenanceCustomFieldService.ts +98 -0
  84. package/Server/Services/ScheduledMaintenanceService.ts +32 -0
  85. package/Server/Services/StatusPagePrivateUserService.ts +103 -3
  86. package/Server/Services/TeamMemberService.ts +78 -0
  87. package/Server/Services/TeamPermissionService.ts +235 -3
  88. package/Server/Services/TelemetryIngestionKeyService.ts +722 -19
  89. package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
  90. package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
  91. package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
  92. package/Server/Services/UserNotificationSettingService.ts +90 -25
  93. package/Server/Services/UserService.ts +95 -0
  94. package/Server/Services/UserTelegramService.ts +326 -5
  95. package/Server/Types/Database/QueryHelper.ts +4 -2
  96. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
  97. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
  98. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
  99. package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
  100. package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
  101. package/Server/Utils/APIKey/AccessPermission.ts +5 -2
  102. package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
  103. package/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.ts +54 -0
  104. package/Server/Utils/CustomField/CustomFieldMappingRegistry.ts +415 -0
  105. package/Server/Utils/CustomField/CustomFieldMappingValidator.ts +335 -0
  106. package/Server/Utils/DataSource/EgressGuard.ts +177 -8
  107. package/Server/Utils/DataSource/HttpFetch.ts +9 -2
  108. package/Server/Utils/EmailRollup/EmailRollupConstants.ts +131 -0
  109. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +925 -0
  110. package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
  111. package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
  112. package/Server/Utils/FrontendEnvironment.ts +40 -0
  113. package/Server/Utils/LLM/LLMService.ts +78 -0
  114. package/Server/Utils/LogRedaction.ts +28 -0
  115. package/Server/Utils/Logger.ts +90 -1
  116. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +338 -77
  117. package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
  118. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
  119. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +30 -4
  120. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
  121. package/Server/Utils/Monitor/MonitorAlert.ts +29 -6
  122. package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
  123. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +159 -15
  124. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
  125. package/Server/Utils/Monitor/MonitorIncident.ts +22 -6
  126. package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
  127. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +72 -0
  128. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
  129. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
  130. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
  131. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
  132. package/Server/Utils/Monitor/SeriesContextEnricher.ts +304 -0
  133. package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
  134. package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
  135. package/Server/Utils/OutboundUserAgent.ts +152 -0
  136. package/Server/Utils/SSRFProtection.ts +217 -10
  137. package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +239 -138
  138. package/Server/Utils/SessionReplay/SessionReplayHealthCounters.ts +305 -0
  139. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +1430 -289
  140. package/Server/Utils/StartServer.ts +53 -36
  141. package/Server/Utils/TelegramVerificationToken.ts +185 -0
  142. package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
  143. package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
  144. package/Server/Utils/Telemetry/PinServiceName.ts +197 -0
  145. package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
  146. package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +38 -16
  147. package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +92 -0
  148. package/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.ts +217 -0
  149. package/Server/Utils/Telemetry.ts +198 -51
  150. package/Server/Utils/VM/VMAPI.ts +1 -0
  151. package/Server/Utils/VM/VMRunner.ts +975 -95
  152. package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
  153. package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +202 -0
  154. package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +134 -33
  155. package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
  156. package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
  157. package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +404 -0
  158. package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
  159. package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
  160. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +486 -9
  161. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
  162. package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
  163. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
  164. package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
  165. package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
  166. package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
  167. package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
  168. package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
  169. package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +41 -5
  170. package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +399 -0
  171. package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
  172. package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
  173. package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
  174. package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
  175. package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
  176. package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
  177. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
  178. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
  179. package/Tests/App/StatusPage/StatusPageLastUpdated.test.tsx +263 -0
  180. package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
  181. package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +753 -0
  182. package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +224 -0
  183. package/Tests/Models/AnalyticsModels/RumSessionReplayColumns.test.ts +262 -0
  184. package/Tests/Models/CustomFieldMappingColumns.test.ts +166 -0
  185. package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +20 -6
  186. package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
  187. package/Tests/ResponsiveVisibility.test.ts +115 -0
  188. package/Tests/ResponsiveVisibility.ts +183 -0
  189. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
  190. package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
  191. package/Tests/Server/API/SessionReplayAPI.test.ts +1940 -216
  192. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +186 -0
  193. package/Tests/Server/API/UserTelegramAPISecurity.test.ts +231 -0
  194. package/Tests/Server/EnvironmentConfigFrontendSecurity.test.ts +234 -0
  195. package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +202 -0
  196. package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +41 -0
  197. package/Tests/Server/Infrastructure/Postgres/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
  198. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
  199. package/Tests/Server/Infrastructure/Postgres/SessionReplayRecordEverySessionByDefaultMigration.test.ts +169 -0
  200. package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
  201. package/Tests/Server/Infrastructure/QueueWorkerTimeout.test.ts +210 -0
  202. package/Tests/Server/Infrastructure/TelemetryExporterDeploymentConfig.test.ts +130 -0
  203. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +4 -1
  204. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +1163 -0
  205. package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +5 -3
  206. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
  207. package/Tests/Server/Services/AddTelemetryIngestionKeyTypeMigration.test.ts +555 -0
  208. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +678 -0
  209. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +276 -28
  210. package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
  211. package/Tests/Server/Services/CustomFieldDropdownOptionsColumnWidth.test.ts +431 -0
  212. package/Tests/Server/Services/CustomFieldMappingService.test.ts +850 -0
  213. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +32 -0
  214. package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
  215. package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
  216. package/Tests/Server/Services/GlobalConfigService.test.ts +414 -1
  217. package/Tests/Server/Services/MetricRawEntityKeyPrune.test.ts +592 -0
  218. package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
  219. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
  220. package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
  221. package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
  222. package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
  223. package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
  224. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +273 -5
  225. package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
  226. package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
  227. package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
  228. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
  229. package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
  230. package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
  231. package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
  232. package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
  233. package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
  234. package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
  235. package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
  236. package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
  237. package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
  238. package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
  239. package/Tests/Server/Services/RoutineEmailSettingsPostgres.test.ts +329 -0
  240. package/Tests/Server/Services/RumSessionReplayViewService.test.ts +267 -0
  241. package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
  242. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +9 -0
  243. package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +9 -0
  244. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +834 -0
  245. package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +814 -0
  246. package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +998 -0
  247. package/Tests/Server/Services/UserEmailChangePasswordResetExpiry.test.ts +472 -0
  248. package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
  249. package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
  250. package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
  251. package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +997 -0
  252. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +110 -1
  253. package/Tests/Server/Services/UserTelegramVerificationSecurity.test.ts +688 -0
  254. package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
  255. package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
  256. package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
  257. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
  258. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
  259. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -0
  260. package/Tests/Server/Utils/AI/SRE/Insights/FixRouting.test.ts +497 -0
  261. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +383 -0
  262. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +7 -3
  263. package/Tests/Server/Utils/AnalyticsDatabase/ClusterConfig.test.ts +315 -0
  264. package/Tests/Server/Utils/Captcha.test.ts +422 -0
  265. package/Tests/Server/Utils/CustomField/CustomFieldMappingValidator.test.ts +437 -0
  266. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +300 -11
  267. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +96 -2
  268. package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
  269. package/Tests/Server/Utils/EmailRollup/EmailRollupBurstWindow.test.ts +83 -0
  270. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
  271. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
  272. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerPreferences.test.ts +362 -0
  273. package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
  274. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +828 -0
  275. package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
  276. package/Tests/Server/Utils/FrontendEnvironment.test.ts +190 -0
  277. package/Tests/Server/Utils/LogRedaction.test.ts +26 -0
  278. package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +23 -9
  279. package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
  280. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +584 -0
  281. package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
  282. package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestHeaderCriteria.test.ts +236 -0
  283. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
  284. package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
  285. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +437 -0
  286. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
  287. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
  288. package/Tests/Server/Utils/Monitor/MonitorTemplateUtilSeriesContext.test.ts +176 -0
  289. package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
  290. package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
  291. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
  292. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
  293. package/Tests/Server/Utils/Monitor/SeriesContextEnricher.test.ts +356 -0
  294. package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
  295. package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
  296. package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
  297. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +595 -0
  298. package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
  299. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +198 -1
  300. package/Tests/Server/Utils/SessionReplay/SessionReplayHealthCounters.test.ts +453 -0
  301. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1378 -0
  302. package/Tests/Server/Utils/SessionReplayOriginAllowListRefactor.test.ts +420 -0
  303. package/Tests/Server/Utils/TelegramVerificationToken.test.ts +253 -0
  304. package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
  305. package/Tests/Server/Utils/Telemetry/PinServiceName.test.ts +666 -0
  306. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriterCapacity.test.ts +458 -0
  307. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +424 -0
  308. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.test.ts +528 -0
  309. package/Tests/Server/Utils/Telemetry.test.ts +456 -66
  310. package/Tests/Server/Utils/TelemetryExporterEnvironment.test.ts +56 -0
  311. package/Tests/Server/Utils/VM/VMRunnerHostBridgeLatency.test.ts +74 -0
  312. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +100 -7
  313. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +1176 -6
  314. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +220 -0
  315. package/Tests/Types/CustomField/CustomFieldValueMapping.test.ts +348 -0
  316. package/Tests/Types/JSONFunctions.test.ts +260 -0
  317. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +422 -53
  318. package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
  319. package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +495 -15
  320. package/Tests/Types/Monitor/DockerSwarmAlertTemplates.test.ts +191 -45
  321. package/Tests/Types/Monitor/HostAlertTemplates.test.ts +370 -42
  322. package/Tests/Types/Monitor/IotAlertTemplates.test.ts +375 -20
  323. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +636 -42
  324. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +189 -0
  325. package/Tests/Types/Monitor/KubernetesTemplateGroupByKeys.test.ts +95 -14
  326. package/Tests/Types/Monitor/MonitorStepDatabaseMonitor.test.ts +243 -0
  327. package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
  328. package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
  329. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
  330. package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
  331. package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +190 -21
  332. package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +352 -22
  333. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +363 -0
  334. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +93 -18
  335. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +259 -0
  336. package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +476 -0
  337. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +136 -0
  338. package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +661 -0
  339. package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +507 -0
  340. package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +270 -0
  341. package/Tests/Types/Monitor/TemplateGroupByKeys.test.ts +38 -10
  342. package/Tests/Types/Monitor/Utils/RecommendationCriteriaAssertions.ts +102 -0
  343. package/Tests/Types/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
  344. package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
  345. package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
  346. package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -0
  347. package/Tests/Types/NotificationSetting/RoutineEmailEvents.test.ts +47 -0
  348. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +608 -0
  349. package/Tests/Types/Rum/SessionReplayCustomEvents.test.ts +434 -0
  350. package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
  351. package/Tests/Types/WebsiteRequest.test.ts +285 -3
  352. package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
  353. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +16 -3
  354. package/Tests/UI/Components/Charts/ChartTrailingBucketGap.test.ts +691 -0
  355. package/Tests/UI/Components/ComponentsModal.test.tsx +12 -4
  356. package/Tests/UI/Components/ComponentsModalUsability.test.tsx +518 -0
  357. package/Tests/UI/Components/CustomFields/CustomFieldsDetailMapping.test.tsx +324 -0
  358. package/Tests/UI/Components/CustomFields/MapFromCustomFieldInput.test.tsx +176 -0
  359. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +484 -0
  360. package/Tests/UI/Components/HeaderRightRail.test.tsx +157 -0
  361. package/Tests/UI/Components/IconDropdownItem.test.tsx +102 -0
  362. package/Tests/UI/Components/JSONTablePrototypePollution.test.tsx +117 -0
  363. package/Tests/UI/Components/KeyboardShortcutsModal.test.tsx +214 -0
  364. package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +561 -0
  365. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +302 -0
  366. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +43 -12
  367. package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
  368. package/Tests/UI/Components/ShortcutDialogGuard.test.tsx +74 -0
  369. package/Tests/UI/Components/SideMenuItem.test.tsx +226 -4
  370. package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
  371. package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -0
  372. package/Tests/UI/Components/StatusPage/ResourceGroupSectionAutoExpand.test.tsx +248 -0
  373. package/Tests/UI/Components/TableCellWrapping.test.tsx +625 -0
  374. package/Tests/UI/Components/TableLoadingStates.test.tsx +205 -0
  375. package/Tests/UI/Components/Workflow/NodePlacement.test.ts +148 -0
  376. package/Tests/UI/Components/Workflow/Workflow.test.tsx +981 -0
  377. package/Tests/UI/ConfigBrowserTelemetry.test.ts +70 -0
  378. package/Tests/UI/Rum/ChunkLoader.test.ts +1036 -2
  379. package/Tests/UI/Rum/FidelityNotices.test.ts +187 -0
  380. package/Tests/UI/Rum/InactivityMap.test.ts +341 -0
  381. package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +259 -0
  382. package/Tests/UI/Rum/RecordingHealthCard.test.tsx +855 -0
  383. package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +594 -0
  384. package/Tests/UI/Rum/ReplayCard.test.tsx +451 -0
  385. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +536 -0
  386. package/Tests/UI/Rum/ReplayEngine.test.ts +2503 -0
  387. package/Tests/UI/Rum/ReplayEngineTypes.test.ts +171 -0
  388. package/Tests/UI/Rum/ReplayHeader.test.tsx +711 -0
  389. package/Tests/UI/Rum/ReplayLink.test.tsx +119 -0
  390. package/Tests/UI/Rum/ReplayPinControl.test.tsx +408 -0
  391. package/Tests/UI/Rum/ReplayPlaybackIntent.test.ts +152 -0
  392. package/Tests/UI/Rum/ReplayRail.test.tsx +1296 -0
  393. package/Tests/UI/Rum/ReplayRailDetail.test.tsx +900 -0
  394. package/Tests/UI/Rum/ReplayScrubber.test.tsx +763 -147
  395. package/Tests/UI/Rum/ReplaySignalTypes.test.ts +189 -0
  396. package/Tests/UI/Rum/ReplaySignals.test.ts +1579 -0
  397. package/Tests/UI/Rum/ReplayStage.test.tsx +396 -473
  398. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +918 -0
  399. package/Tests/UI/Rum/ReplayTimeline.test.tsx +696 -0
  400. package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +499 -0
  401. package/Tests/UI/Rum/SessionReplaySearchBar.test.tsx +346 -0
  402. package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +545 -0
  403. package/Tests/UI/Rum/SessionReplayTable.test.tsx +991 -0
  404. package/Tests/UI/Rum/TargetedCapturePanel.test.tsx +254 -0
  405. package/Tests/UI/Telemetry/BrowserExporterIsolation.test.ts +71 -0
  406. package/Tests/UI/Utils/GlobalKeyboardShortcut.test.ts +344 -0
  407. package/Tests/UI/Utils/PageScrollLock.test.tsx +377 -0
  408. package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
  409. package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
  410. package/Tests/Utils/API.test.ts +308 -0
  411. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
  412. package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
  413. package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
  414. package/Tests/Utils/HTTPResponseBodyReader.test.ts +323 -0
  415. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
  416. package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
  417. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
  418. package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
  419. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
  420. package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
  421. package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
  422. package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
  423. package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
  424. package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
  425. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
  426. package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
  427. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
  428. package/Tests/Utils/NetworkDiscovery/DiscoveryScanStatus.test.ts +117 -0
  429. package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
  430. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
  431. package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -0
  432. package/Tests/Utils/Rum/ChunkMath.test.ts +83 -0
  433. package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +993 -0
  434. package/Tests/Utils/Rum/SessionReplayStringMap.test.ts +245 -0
  435. package/Tests/Utils/StatusPage/ResourceSearch.test.ts +631 -0
  436. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
  437. package/Tests/Utils/Telemetry/OriginAllowList.test.ts +633 -0
  438. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +461 -0
  439. package/Tests/Utils/ValueFormatter.test.ts +148 -0
  440. package/Types/AI/ExceptionAIClassification.ts +10 -24
  441. package/Types/CustomField/CustomFieldMappingCatalog.ts +161 -0
  442. package/Types/CustomField/CustomFieldMappingSourceResource.ts +19 -0
  443. package/Types/CustomField/CustomFieldValueMapping.ts +288 -0
  444. package/Types/Email/EmailTemplateType.ts +2 -0
  445. package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
  446. package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
  447. package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
  448. package/Types/Exception/ApiException.ts +10 -0
  449. package/Types/Exception/BadDataException.ts +11 -0
  450. package/Types/Exception/BadRequestException.ts +11 -0
  451. package/Types/Exception/Exception.ts +65 -0
  452. package/Types/Exception/ForbiddenException.ts +10 -0
  453. package/Types/Exception/NotAuthenticatedException.ts +10 -0
  454. package/Types/Exception/NotAuthorizedException.ts +10 -0
  455. package/Types/Exception/NotFoundException.ts +11 -0
  456. package/Types/Exception/PayloadTooLargeException.ts +11 -0
  457. package/Types/Exception/PaymentRequiredException.ts +10 -0
  458. package/Types/Exception/ServiceUnavailableException.ts +10 -0
  459. package/Types/Exception/SsoAuthorizationException.ts +10 -0
  460. package/Types/Exception/TenantNotFoundException.ts +11 -0
  461. package/Types/Exception/TimeoutException.ts +10 -0
  462. package/Types/Exception/TooManyRequestsException.ts +10 -0
  463. package/Types/Exception/UnableToReachServer.ts +10 -0
  464. package/Types/Exception/WebsiteRequestException.ts +10 -0
  465. package/Types/Icon/IconProp.ts +1 -0
  466. package/Types/JSONFunctions.ts +189 -43
  467. package/Types/Monitor/CephAlertTemplates.ts +157 -195
  468. package/Types/Monitor/CriteriaFilter.ts +60 -2
  469. package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
  470. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
  471. package/Types/Monitor/DockerAlertTemplates.ts +338 -128
  472. package/Types/Monitor/DockerSwarmAlertTemplates.ts +95 -112
  473. package/Types/Monitor/HostAlertTemplates.ts +302 -130
  474. package/Types/Monitor/IotAlertTemplates.ts +112 -104
  475. package/Types/Monitor/KubernetesAlertTemplates.ts +415 -224
  476. package/Types/Monitor/KubernetesMetricCatalog.ts +23 -19
  477. package/Types/Monitor/MonitorCriteriaInstance.ts +76 -0
  478. package/Types/Monitor/MonitorMetricType.ts +71 -0
  479. package/Types/Monitor/MonitorStep.ts +76 -0
  480. package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
  481. package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
  482. package/Types/Monitor/MonitorType.ts +47 -1
  483. package/Types/Monitor/PodmanAlertTemplates.ts +116 -163
  484. package/Types/Monitor/ProxmoxAlertTemplates.ts +217 -99
  485. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +98 -6
  486. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +44 -7
  487. package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +383 -0
  488. package/Types/Monitor/RumAlertTemplates.ts +46 -7
  489. package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +596 -0
  490. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +554 -0
  491. package/Types/Monitor/ServiceAlertTemplates.ts +98 -11
  492. package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
  493. package/Types/Monitor/SqlConnectionConfig.ts +31 -0
  494. package/Types/Monitor/UptimeHistoryLabels.ts +56 -0
  495. package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
  496. package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
  497. package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
  498. package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
  499. package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
  500. package/Types/NotificationSetting/RoutineEmailEvents.ts +30 -0
  501. package/Types/Permission.ts +90 -0
  502. package/Types/Probe/ProbeMonitorResponse.ts +16 -0
  503. package/Types/Rum/SessionReplay.ts +209 -0
  504. package/Types/Rum/SessionReplayApi.ts +722 -0
  505. package/Types/Rum/SessionReplayCaptureTrigger.ts +21 -12
  506. package/Types/Rum/SessionReplayConsentMode.ts +11 -7
  507. package/Types/Rum/SessionReplayCustomEvents.ts +549 -0
  508. package/Types/Rum/SessionReplayHealth.ts +238 -0
  509. package/Types/Telemetry/ErrorClass.ts +274 -0
  510. package/Types/Telemetry/TelemetryIngestSurface.ts +95 -0
  511. package/Types/Telemetry/TelemetryIngestionKeyPolicy.ts +75 -0
  512. package/Types/Telemetry/TelemetryIngestionKeyType.ts +29 -0
  513. package/Types/Telemetry/UnitOfWork.ts +59 -0
  514. package/Types/WebsiteRequest.ts +85 -3
  515. package/UI/Components/Charts/Area/AreaChart.tsx +13 -2
  516. package/UI/Components/Charts/Bar/BarChart.tsx +6 -2
  517. package/UI/Components/Charts/Line/LineChart.tsx +13 -2
  518. package/UI/Components/Charts/Types/XAxis/XAxis.ts +29 -0
  519. package/UI/Components/Charts/Utils/DataPoint.ts +22 -3
  520. package/UI/Components/Charts/Utils/TimeAnnotation.ts +76 -9
  521. package/UI/Components/Charts/Utils/XAxis.ts +217 -0
  522. package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
  523. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +143 -25
  524. package/UI/Components/CustomFields/MapFromCustomFieldInput.tsx +216 -0
  525. package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
  526. package/UI/Components/Graphs/DayUptimeGraph.tsx +173 -8
  527. package/UI/Components/Graphs/UptimeBarTooltip.tsx +22 -278
  528. package/UI/Components/Graphs/UptimeDaySummary.tsx +327 -0
  529. package/UI/Components/Header/Header.tsx +25 -9
  530. package/UI/Components/Header/IconDropdown/IconDropdownItem.tsx +10 -1
  531. package/UI/Components/Header/IconDropdown/IconDropdownMenu.tsx +6 -1
  532. package/UI/Components/Header/ProjectPicker/ProjectPicker.tsx +6 -1
  533. package/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.tsx +6 -1
  534. package/UI/Components/Icon/Icon.tsx +11 -0
  535. package/UI/Components/JSONTable/JSONTable.tsx +2 -2
  536. package/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.tsx +125 -0
  537. package/UI/Components/KeyboardShortcut/Screenshots/README.md +19 -0
  538. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-command-palette.png +0 -0
  539. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog-dark.png +0 -0
  540. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog.png +0 -0
  541. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-help-menu.png +0 -0
  542. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-narrow.png +0 -0
  543. package/UI/Components/Modal/Modal.tsx +2 -8
  544. package/UI/Components/ModelTable/Column.ts +15 -0
  545. package/UI/Components/Monitor/SeriesDebugCommandsViewer.tsx +64 -0
  546. package/UI/Components/Monitor/SeriesLabelsViewer.tsx +93 -0
  547. package/UI/Components/MonitorGraphs/Uptime.tsx +14 -2
  548. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +63 -10
  549. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +88 -0
  550. package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
  551. package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
  552. package/UI/Components/SideMenu/SideMenu.tsx +123 -5
  553. package/UI/Components/SideMenu/SideMenuItem.tsx +76 -84
  554. package/UI/Components/SideMenu/SideMenuSection.tsx +55 -23
  555. package/UI/Components/SideOver/SideOver.tsx +21 -20
  556. package/UI/Components/StatusPage/ResourceGroupSection.tsx +40 -0
  557. package/UI/Components/Table/CellClassName.ts +81 -0
  558. package/UI/Components/Table/TableRow.tsx +20 -14
  559. package/UI/Components/Table/TableSkeletonRows.tsx +9 -9
  560. package/UI/Components/Table/Types/Column.ts +36 -0
  561. package/UI/Components/Tooltip/Tooltip.tsx +11 -1
  562. package/UI/Components/Workflow/ComponentsModal.tsx +60 -39
  563. package/UI/Components/Workflow/NodePlacement.ts +57 -0
  564. package/UI/Components/Workflow/Workflow.tsx +47 -18
  565. package/UI/Config.ts +15 -33
  566. package/UI/Utils/GlobalKeyboardShortcut.ts +208 -0
  567. package/UI/Utils/PageScrollLock.ts +79 -3
  568. package/UI/Utils/PermissionGate.ts +61 -0
  569. package/UI/Utils/SensitiveUrlToken.ts +112 -0
  570. package/UI/Utils/Telemetry/BrowserTelemetryConfig.ts +28 -0
  571. package/UI/Utils/Telemetry/Telemetry.ts +10 -8
  572. package/UI/Utils/TestLLMProvider.ts +11 -0
  573. package/Utils/API.ts +129 -3
  574. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
  575. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
  576. package/Utils/HTTPResponseBodyReader.ts +221 -0
  577. package/Utils/Monitor/MonitorMetricType.ts +153 -1
  578. package/Utils/Monitor/NetworkTopologyUtil.ts +23 -3
  579. package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
  580. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
  581. package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
  582. package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
  583. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
  584. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
  585. package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
  586. package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +77 -0
  587. package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
  588. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
  589. package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
  590. package/Utils/Rum/ChunkMath.ts +106 -0
  591. package/Utils/Rum/SessionReplayHealth.ts +732 -0
  592. package/Utils/Rum/SessionReplayStringMap.ts +226 -0
  593. package/Utils/Schema/ModelSchema.ts +1 -0
  594. package/Utils/StatusPage/ResourceSearch.ts +290 -0
  595. package/Utils/Telemetry/OriginAllowList.ts +355 -0
  596. package/Utils/Uptime/DayUptimeGraphUtil.ts +205 -0
  597. package/Utils/ValueFormatter.ts +35 -1
  598. package/build/dist/Models/AnalyticsModels/RumSession.js +102 -19
  599. package/build/dist/Models/AnalyticsModels/RumSession.js.map +1 -1
  600. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js +11 -9
  601. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js.map +1 -1
  602. package/build/dist/Models/AnalyticsModels/Span.js +14 -0
  603. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  604. package/build/dist/Models/DatabaseModels/AlertCustomField.js +79 -3
  605. package/build/dist/Models/DatabaseModels/AlertCustomField.js.map +1 -1
  606. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js +3 -27
  607. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js.map +1 -1
  608. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +59 -0
  609. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  610. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +79 -3
  611. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  612. package/build/dist/Models/DatabaseModels/Index.js +10 -0
  613. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  614. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js +79 -3
  615. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js.map +1 -1
  616. package/build/dist/Models/DatabaseModels/Monitor.js +75 -0
  617. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  618. package/build/dist/Models/DatabaseModels/MonitorCustomField.js +79 -3
  619. package/build/dist/Models/DatabaseModels/MonitorCustomField.js.map +1 -1
  620. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js +713 -0
  621. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
  622. package/build/dist/Models/DatabaseModels/NetworkDevice.js +180 -1
  623. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  624. package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
  625. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
  626. package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
  627. package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
  628. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
  629. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
  630. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js +79 -3
  631. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js.map +1 -1
  632. package/build/dist/Models/DatabaseModels/RumApplication.js +6 -6
  633. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  634. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js +79 -3
  635. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js.map +1 -1
  636. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js +79 -3
  637. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js.map +1 -1
  638. package/build/dist/Models/DatabaseModels/TeamCustomField.js +79 -3
  639. package/build/dist/Models/DatabaseModels/TeamCustomField.js.map +1 -1
  640. package/build/dist/Models/DatabaseModels/TeamMember.js +0 -9
  641. package/build/dist/Models/DatabaseModels/TeamMember.js.map +1 -1
  642. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js +79 -3
  643. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js.map +1 -1
  644. package/build/dist/Models/DatabaseModels/TeamPermission.js +3 -24
  645. package/build/dist/Models/DatabaseModels/TeamPermission.js.map +1 -1
  646. package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
  647. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  648. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +267 -0
  649. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
  650. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js +363 -0
  651. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
  652. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
  653. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
  654. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
  655. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
  656. package/build/dist/Models/DatabaseModels/UserTelegram.js +0 -4
  657. package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
  658. package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
  659. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  660. package/build/dist/Server/API/LlmProviderAPI.js +108 -13
  661. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  662. package/build/dist/Server/API/TelemetryAPI.js +769 -109
  663. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  664. package/build/dist/Server/API/UserNotificationSettingAPI.js +35 -0
  665. package/build/dist/Server/API/UserNotificationSettingAPI.js.map +1 -0
  666. package/build/dist/Server/API/UserTelegramAPI.js +28 -6
  667. package/build/dist/Server/API/UserTelegramAPI.js.map +1 -1
  668. package/build/dist/Server/EnvironmentConfig.js +41 -2
  669. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  670. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
  671. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
  672. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
  673. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
  674. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
  675. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
  676. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
  677. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
  678. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
  679. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
  680. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
  681. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js.map +1 -0
  682. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js +60 -0
  683. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js.map +1 -0
  684. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js +53 -0
  685. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js.map +1 -0
  686. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js +82 -0
  687. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js.map +1 -0
  688. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js +46 -0
  689. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js.map +1 -0
  690. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
  691. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  692. package/build/dist/Server/Infrastructure/QueueWorker.js +52 -12
  693. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  694. package/build/dist/Server/Infrastructure/Semaphore.js +1 -0
  695. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  696. package/build/dist/Server/Middleware/BearerTokenAuthorization.js +12 -0
  697. package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
  698. package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
  699. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  700. package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
  701. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
  702. package/build/dist/Server/Middleware/TelemetryIngest.js +326 -8
  703. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  704. package/build/dist/Server/Services/AIBillingService.js +70 -16
  705. package/build/dist/Server/Services/AIBillingService.js.map +1 -1
  706. package/build/dist/Server/Services/AccessTokenService.js +1 -0
  707. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  708. package/build/dist/Server/Services/AlertCustomFieldService.js +93 -0
  709. package/build/dist/Server/Services/AlertCustomFieldService.js.map +1 -1
  710. package/build/dist/Server/Services/AlertService.js +34 -0
  711. package/build/dist/Server/Services/AlertService.js.map +1 -1
  712. package/build/dist/Server/Services/ApiKeyPermissionService.js +331 -28
  713. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  714. package/build/dist/Server/Services/CustomFieldMappingService.js +614 -0
  715. package/build/dist/Server/Services/CustomFieldMappingService.js.map +1 -0
  716. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js +167 -0
  717. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
  718. package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
  719. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  720. package/build/dist/Server/Services/GlobalConfigService.js +133 -0
  721. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  722. package/build/dist/Server/Services/IncidentCustomFieldService.js +93 -0
  723. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  724. package/build/dist/Server/Services/IncidentService.js +32 -0
  725. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  726. package/build/dist/Server/Services/Index.js +10 -0
  727. package/build/dist/Server/Services/Index.js.map +1 -1
  728. package/build/dist/Server/Services/MetricService.js +163 -0
  729. package/build/dist/Server/Services/MetricService.js.map +1 -1
  730. package/build/dist/Server/Services/MonitorService.js +148 -21
  731. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  732. package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
  733. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  734. package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
  735. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  736. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
  737. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
  738. package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
  739. package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
  740. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +89 -36
  741. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  742. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
  743. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  744. package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
  745. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  746. package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
  747. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  748. package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
  749. package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
  750. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
  751. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
  752. package/build/dist/Server/Services/NotificationService.js +80 -17
  753. package/build/dist/Server/Services/NotificationService.js.map +1 -1
  754. package/build/dist/Server/Services/ProjectService.js +88 -30
  755. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  756. package/build/dist/Server/Services/RoutineEmailSettingsService.js +69 -0
  757. package/build/dist/Server/Services/RoutineEmailSettingsService.js.map +1 -0
  758. package/build/dist/Server/Services/RumSessionReplayViewService.js +86 -24
  759. package/build/dist/Server/Services/RumSessionReplayViewService.js.map +1 -1
  760. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js +93 -0
  761. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js.map +1 -1
  762. package/build/dist/Server/Services/ScheduledMaintenanceService.js +29 -0
  763. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  764. package/build/dist/Server/Services/StatusPagePrivateUserService.js +92 -2
  765. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  766. package/build/dist/Server/Services/TeamMemberService.js +62 -2
  767. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  768. package/build/dist/Server/Services/TeamPermissionService.js +166 -3
  769. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  770. package/build/dist/Server/Services/TelemetryIngestionKeyService.js +562 -18
  771. package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
  772. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js +76 -0
  773. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
  774. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
  775. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
  776. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
  777. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
  778. package/build/dist/Server/Services/UserNotificationSettingService.js +66 -20
  779. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  780. package/build/dist/Server/Services/UserService.js +90 -0
  781. package/build/dist/Server/Services/UserService.js.map +1 -1
  782. package/build/dist/Server/Services/UserTelegramService.js +257 -4
  783. package/build/dist/Server/Services/UserTelegramService.js.map +1 -1
  784. package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
  785. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  786. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
  787. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  788. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
  789. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  790. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
  791. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  792. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
  793. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
  794. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
  795. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
  796. package/build/dist/Server/Utils/APIKey/AccessPermission.js +2 -2
  797. package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
  798. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js +59 -0
  799. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
  800. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js +27 -0
  801. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js.map +1 -0
  802. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js +226 -0
  803. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js.map +1 -0
  804. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js +189 -0
  805. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js.map +1 -0
  806. package/build/dist/Server/Utils/DataSource/EgressGuard.js +121 -7
  807. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  808. package/build/dist/Server/Utils/DataSource/HttpFetch.js +2 -1
  809. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
  810. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +124 -0
  811. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
  812. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +733 -0
  813. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
  814. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
  815. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
  816. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
  817. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
  818. package/build/dist/Server/Utils/FrontendEnvironment.js +33 -0
  819. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -0
  820. package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
  821. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  822. package/build/dist/Server/Utils/LogRedaction.js +28 -0
  823. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  824. package/build/dist/Server/Utils/Logger.js +73 -1
  825. package/build/dist/Server/Utils/Logger.js.map +1 -1
  826. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +287 -68
  827. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  828. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js +141 -0
  829. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
  830. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  831. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  832. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +20 -4
  833. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  834. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +51 -1
  835. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  836. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +29 -6
  837. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  838. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
  839. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
  840. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +125 -13
  841. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  842. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
  843. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  844. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
  845. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  846. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  847. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  848. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +54 -0
  849. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  850. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
  851. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  852. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
  853. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  854. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
  855. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  856. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
  857. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  858. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js +237 -0
  859. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js.map +1 -0
  860. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js +30 -17
  861. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
  862. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
  863. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
  864. package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
  865. package/build/dist/Server/Utils/OutboundUserAgent.js.map +1 -0
  866. package/build/dist/Server/Utils/SSRFProtection.js +136 -9
  867. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  868. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +174 -89
  869. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
  870. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js +223 -0
  871. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js.map +1 -0
  872. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +945 -164
  873. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  874. package/build/dist/Server/Utils/StartServer.js +41 -28
  875. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  876. package/build/dist/Server/Utils/TelegramVerificationToken.js +129 -0
  877. package/build/dist/Server/Utils/TelegramVerificationToken.js.map +1 -0
  878. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +28 -8
  879. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  880. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
  881. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js.map +1 -0
  882. package/build/dist/Server/Utils/Telemetry/PinServiceName.js +163 -0
  883. package/build/dist/Server/Utils/Telemetry/PinServiceName.js.map +1 -0
  884. package/build/dist/Server/Utils/Telemetry/SpanUtil.js +29 -0
  885. package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
  886. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +28 -15
  887. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -1
  888. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +64 -0
  889. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -0
  890. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js +171 -0
  891. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js.map +1 -0
  892. package/build/dist/Server/Utils/Telemetry.js +162 -46
  893. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  894. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  895. package/build/dist/Server/Utils/VM/VMRunner.js +780 -69
  896. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  897. package/build/dist/Types/AI/ExceptionAIClassification.js +10 -24
  898. package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -1
  899. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +60 -0
  900. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -0
  901. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js +20 -0
  902. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js.map +1 -0
  903. package/build/dist/Types/CustomField/CustomFieldValueMapping.js +141 -0
  904. package/build/dist/Types/CustomField/CustomFieldValueMapping.js.map +1 -0
  905. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  906. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  907. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
  908. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
  909. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
  910. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
  911. package/build/dist/Types/Exception/ApiException.js +9 -0
  912. package/build/dist/Types/Exception/ApiException.js.map +1 -1
  913. package/build/dist/Types/Exception/BadDataException.js +10 -0
  914. package/build/dist/Types/Exception/BadDataException.js.map +1 -1
  915. package/build/dist/Types/Exception/BadRequestException.js +10 -0
  916. package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
  917. package/build/dist/Types/Exception/Exception.js +56 -0
  918. package/build/dist/Types/Exception/Exception.js.map +1 -1
  919. package/build/dist/Types/Exception/ForbiddenException.js +9 -0
  920. package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
  921. package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
  922. package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
  923. package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
  924. package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
  925. package/build/dist/Types/Exception/NotFoundException.js +10 -0
  926. package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
  927. package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
  928. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
  929. package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
  930. package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
  931. package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
  932. package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
  933. package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
  934. package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
  935. package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
  936. package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
  937. package/build/dist/Types/Exception/TimeoutException.js +9 -0
  938. package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
  939. package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
  940. package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
  941. package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
  942. package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
  943. package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
  944. package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
  945. package/build/dist/Types/Icon/IconProp.js +1 -0
  946. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  947. package/build/dist/Types/JSONFunctions.js +118 -37
  948. package/build/dist/Types/JSONFunctions.js.map +1 -1
  949. package/build/dist/Types/Monitor/CephAlertTemplates.js +130 -171
  950. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
  951. package/build/dist/Types/Monitor/CriteriaFilter.js +45 -2
  952. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  953. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
  954. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
  955. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
  956. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
  957. package/build/dist/Types/Monitor/DockerAlertTemplates.js +286 -121
  958. package/build/dist/Types/Monitor/DockerAlertTemplates.js.map +1 -1
  959. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js +84 -105
  960. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js.map +1 -1
  961. package/build/dist/Types/Monitor/HostAlertTemplates.js +250 -122
  962. package/build/dist/Types/Monitor/HostAlertTemplates.js.map +1 -1
  963. package/build/dist/Types/Monitor/IotAlertTemplates.js +81 -81
  964. package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
  965. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +375 -215
  966. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  967. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +19 -19
  968. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
  969. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +70 -0
  970. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  971. package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
  972. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  973. package/build/dist/Types/Monitor/MonitorStep.js +54 -0
  974. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  975. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
  976. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
  977. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
  978. package/build/dist/Types/Monitor/MonitorType.js +45 -1
  979. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  980. package/build/dist/Types/Monitor/PodmanAlertTemplates.js +104 -153
  981. package/build/dist/Types/Monitor/PodmanAlertTemplates.js.map +1 -1
  982. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +156 -91
  983. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
  984. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +67 -6
  985. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  986. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +38 -7
  987. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  988. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +261 -0
  989. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -0
  990. package/build/dist/Types/Monitor/RumAlertTemplates.js +46 -7
  991. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  992. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +422 -0
  993. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -0
  994. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +441 -0
  995. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -0
  996. package/build/dist/Types/Monitor/ServiceAlertTemplates.js +79 -15
  997. package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -1
  998. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
  999. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
  1000. package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
  1001. package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
  1002. package/build/dist/Types/Monitor/UptimeHistoryLabels.js +17 -0
  1003. package/build/dist/Types/Monitor/UptimeHistoryLabels.js.map +1 -0
  1004. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
  1005. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
  1006. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
  1007. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
  1008. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
  1009. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
  1010. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
  1011. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
  1012. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
  1013. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js.map +1 -0
  1014. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js +29 -0
  1015. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js.map +1 -0
  1016. package/build/dist/Types/Permission.js +80 -0
  1017. package/build/dist/Types/Permission.js.map +1 -1
  1018. package/build/dist/Types/Rum/SessionReplay.js +117 -0
  1019. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  1020. package/build/dist/Types/Rum/SessionReplayApi.js +181 -0
  1021. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -0
  1022. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js +21 -12
  1023. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js.map +1 -1
  1024. package/build/dist/Types/Rum/SessionReplayConsentMode.js +11 -7
  1025. package/build/dist/Types/Rum/SessionReplayConsentMode.js.map +1 -1
  1026. package/build/dist/Types/Rum/SessionReplayCustomEvents.js +172 -0
  1027. package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -0
  1028. package/build/dist/Types/Rum/SessionReplayHealth.js +37 -0
  1029. package/build/dist/Types/Rum/SessionReplayHealth.js.map +1 -0
  1030. package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
  1031. package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
  1032. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +85 -0
  1033. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -0
  1034. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js +15 -0
  1035. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js.map +1 -0
  1036. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js +30 -0
  1037. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js.map +1 -0
  1038. package/build/dist/Types/Telemetry/UnitOfWork.js +59 -0
  1039. package/build/dist/Types/Telemetry/UnitOfWork.js.map +1 -0
  1040. package/build/dist/Types/WebsiteRequest.js +55 -3
  1041. package/build/dist/Types/WebsiteRequest.js.map +1 -1
  1042. package/build/dist/UI/Components/Charts/Area/AreaChart.js +13 -2
  1043. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  1044. package/build/dist/UI/Components/Charts/Bar/BarChart.js +6 -2
  1045. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  1046. package/build/dist/UI/Components/Charts/Line/LineChart.js +13 -2
  1047. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  1048. package/build/dist/UI/Components/Charts/Types/XAxis/XAxis.js.map +1 -1
  1049. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -3
  1050. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  1051. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +40 -9
  1052. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  1053. package/build/dist/UI/Components/Charts/Utils/XAxis.js +186 -0
  1054. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  1055. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +2 -7
  1056. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  1057. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +80 -6
  1058. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  1059. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js +118 -0
  1060. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js.map +1 -0
  1061. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +3 -0
  1062. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  1063. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +112 -7
  1064. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  1065. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -162
  1066. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  1067. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js +181 -0
  1068. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -0
  1069. package/build/dist/UI/Components/Header/Header.js +2 -3
  1070. package/build/dist/UI/Components/Header/Header.js.map +1 -1
  1071. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js +2 -1
  1072. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js.map +1 -1
  1073. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js +7 -1
  1074. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js.map +1 -1
  1075. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js +7 -1
  1076. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js.map +1 -1
  1077. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js +7 -1
  1078. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js.map +1 -1
  1079. package/build/dist/UI/Components/Icon/Icon.js +5 -0
  1080. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  1081. package/build/dist/UI/Components/JSONTable/JSONTable.js +2 -2
  1082. package/build/dist/UI/Components/JSONTable/JSONTable.js.map +1 -1
  1083. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js +35 -0
  1084. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js.map +1 -0
  1085. package/build/dist/UI/Components/Modal/Modal.js +2 -7
  1086. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  1087. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js +34 -0
  1088. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js.map +1 -0
  1089. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js +49 -0
  1090. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js.map +1 -0
  1091. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +1 -1
  1092. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  1093. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +32 -6
  1094. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  1095. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +77 -0
  1096. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  1097. package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
  1098. package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
  1099. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
  1100. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
  1101. package/build/dist/UI/Components/SideMenu/SideMenu.js +67 -5
  1102. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  1103. package/build/dist/UI/Components/SideMenu/SideMenuItem.js +49 -53
  1104. package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
  1105. package/build/dist/UI/Components/SideMenu/SideMenuSection.js +25 -7
  1106. package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
  1107. package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
  1108. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  1109. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +22 -1
  1110. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -1
  1111. package/build/dist/UI/Components/Table/CellClassName.js +55 -0
  1112. package/build/dist/UI/Components/Table/CellClassName.js.map +1 -0
  1113. package/build/dist/UI/Components/Table/TableRow.js +16 -13
  1114. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  1115. package/build/dist/UI/Components/Table/TableSkeletonRows.js +9 -8
  1116. package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -1
  1117. package/build/dist/UI/Components/Tooltip/Tooltip.js +25 -1
  1118. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  1119. package/build/dist/UI/Components/Workflow/ComponentsModal.js +47 -30
  1120. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  1121. package/build/dist/UI/Components/Workflow/NodePlacement.js +37 -0
  1122. package/build/dist/UI/Components/Workflow/NodePlacement.js.map +1 -0
  1123. package/build/dist/UI/Components/Workflow/Workflow.js +35 -18
  1124. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  1125. package/build/dist/UI/Config.js +10 -20
  1126. package/build/dist/UI/Config.js.map +1 -1
  1127. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js +138 -0
  1128. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js.map +1 -0
  1129. package/build/dist/UI/Utils/PageScrollLock.js +31 -3
  1130. package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
  1131. package/build/dist/UI/Utils/PermissionGate.js +42 -1
  1132. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  1133. package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
  1134. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -0
  1135. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js +14 -0
  1136. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js.map +1 -0
  1137. package/build/dist/UI/Utils/Telemetry/Telemetry.js +7 -5
  1138. package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
  1139. package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
  1140. package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
  1141. package/build/dist/Utils/API.js +67 -5
  1142. package/build/dist/Utils/API.js.map +1 -1
  1143. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
  1144. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
  1145. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
  1146. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  1147. package/build/dist/Utils/HTTPResponseBodyReader.js +157 -0
  1148. package/build/dist/Utils/HTTPResponseBodyReader.js.map +1 -0
  1149. package/build/dist/Utils/Monitor/MonitorMetricType.js +109 -1
  1150. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  1151. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +8 -3
  1152. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  1153. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
  1154. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
  1155. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
  1156. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  1157. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
  1158. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
  1159. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
  1160. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
  1161. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
  1162. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  1163. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
  1164. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  1165. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
  1166. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
  1167. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +69 -0
  1168. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -0
  1169. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
  1170. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
  1171. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
  1172. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  1173. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
  1174. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js.map +1 -0
  1175. package/build/dist/Utils/Rum/ChunkMath.js +76 -0
  1176. package/build/dist/Utils/Rum/ChunkMath.js.map +1 -1
  1177. package/build/dist/Utils/Rum/SessionReplayHealth.js +534 -0
  1178. package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -0
  1179. package/build/dist/Utils/Rum/SessionReplayStringMap.js +165 -0
  1180. package/build/dist/Utils/Rum/SessionReplayStringMap.js.map +1 -0
  1181. package/build/dist/Utils/Schema/ModelSchema.js +1 -0
  1182. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  1183. package/build/dist/Utils/StatusPage/ResourceSearch.js +200 -0
  1184. package/build/dist/Utils/StatusPage/ResourceSearch.js.map +1 -0
  1185. package/build/dist/Utils/Telemetry/OriginAllowList.js +299 -0
  1186. package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -0
  1187. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +147 -0
  1188. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -0
  1189. package/build/dist/Utils/ValueFormatter.js +32 -1
  1190. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  1191. package/package.json +2 -2
@@ -0,0 +1,2159 @@
1
+ import MonitorService from "./MonitorService";
2
+ import MonitorTemplateService from "./MonitorTemplateService";
3
+ import NetworkAlertPolicyService from "./NetworkAlertPolicyService";
4
+ import NetworkDeviceService from "./NetworkDeviceService";
5
+ import ProjectService, { CurrentPlan } from "./ProjectService";
6
+ import Monitor from "../../Models/DatabaseModels/Monitor";
7
+ import MonitorTemplate from "../../Models/DatabaseModels/MonitorTemplate";
8
+ import NetworkAlertPolicy from "../../Models/DatabaseModels/NetworkAlertPolicy";
9
+ import NetworkDevice from "../../Models/DatabaseModels/NetworkDevice";
10
+ import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
11
+ import {
12
+ AllowedActiveMonitorCountInFreePlan,
13
+ IsBillingEnabled,
14
+ } from "../EnvironmentConfig";
15
+ import Query from "../Types/Database/Query";
16
+ import QueryHelper from "../Types/Database/QueryHelper";
17
+ import Select from "../Types/Database/Select";
18
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
19
+ import logger, { LogAttributes } from "../Utils/Logger";
20
+ import SortOrder from "../../Types/BaseDatabase/SortOrder";
21
+ import { PlanType } from "../../Types/Billing/SubscriptionPlan";
22
+ import LIMIT_MAX, { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
23
+ import OneUptimeDate from "../../Types/Date";
24
+ import MonitorType, {
25
+ MonitorTypeHelper,
26
+ } from "../../Types/Monitor/MonitorType";
27
+ import NetworkAlertPolicyScope, {
28
+ NetworkAlertPolicyScopeUtil,
29
+ } from "../../Types/NetworkDevice/NetworkAlertPolicyScope";
30
+ import { NetworkDeviceMonitoringMethodUtil } from "../../Types/NetworkDevice/NetworkDeviceMonitoringMethod";
31
+ import ObjectID from "../../Types/ObjectID";
32
+ import PartialEntity from "../../Types/Database/PartialEntity";
33
+ import PositiveNumber from "../../Types/PositiveNumber";
34
+ import NetworkDeviceMonitorTemplateUtil from "../../Utils/Monitor/NetworkDeviceMonitorTemplateUtil";
35
+
36
+ /*
37
+ * The engine behind Network Alert Policies: the ONE place in the product
38
+ * that creates or deletes a policy-owned Monitor.
39
+ *
40
+ * A policy is intent — "every device in these sites, with these roles, with
41
+ * these labels, gets a Network Device monitor cloned from this template".
42
+ * The monitors are the consequence, and they are billed and they own
43
+ * incident history, so every path that could produce or destroy one funnels
44
+ * through `reconcileDevice(projectId, deviceId)`. Device created, device
45
+ * re-sited, device re-labelled, device archived, policy saved, policy
46
+ * enabled, policy scope widened, the five-minute sweep — all of them end up
47
+ * calling the same function for one device, under one Redis lock, and that
48
+ * function computes:
49
+ *
50
+ * DESIRED every enabled policy of the project whose scope matches this
51
+ * device, PROVIDED the device is provisionable at all: not
52
+ * archived, not monitor-backed (a monitor-backed device's health
53
+ * IS a monitor's — a policy monitor on it would poll nothing),
54
+ * and carrying a probe (nothing polls a device without one, so a
55
+ * monitor on it would sit Pending forever and still be billed).
56
+ *
57
+ * ACTUAL the monitors whose provenance says a policy made them:
58
+ * `autoProvisionedNetworkDeviceId = this device AND
59
+ * networkAlertPolicyId IS NOT NULL`. Both halves matter. Without
60
+ * the first the engine would wander outside the device; without
61
+ * the second it would treat a hand-made monitor, or one an
62
+ * auto-import rule provisioned, as its own and delete it.
63
+ *
64
+ * and applies the difference. There is deliberately no "create the monitors
65
+ * for a new policy" path and no "delete the monitors for a shrunk scope"
66
+ * path: both are the same difference, computed per device, so the two can
67
+ * never disagree about who owns what.
68
+ *
69
+ * WHAT THE ENGINE WILL NOT DO, ever:
70
+ *
71
+ * - Touch a monitor another policy owns. Ownership is the PAIR
72
+ * (networkAlertPolicyId, monitorTemplateId): a monitor is policy P's
73
+ * current monitor only while it carries P's id AND the template P names
74
+ * right now. A monitor stamped with a different policy's id is left
75
+ * exactly where it is.
76
+ * - Delete a hand-made monitor. A Network Device monitor with no
77
+ * `networkAlertPolicyId` is not in ACTUAL at all, so a scope that shrinks
78
+ * away from a device deletes only the rows stamped with the policy that
79
+ * shrank.
80
+ * - Duplicate an unowned monitor. If a (device, template) monitor already
81
+ * exists without an owner — an auto-import rule's, or one a person built
82
+ * from the same template — the engine ADOPTS it by stamping its
83
+ * `networkAlertPolicyId`, rather than trying to create a second one and
84
+ * failing forever on Monitor's partial unique index on
85
+ * (autoProvisionedNetworkDeviceId, monitorTemplateId).
86
+ * - Rewrite a policy's scope. Stale ids in a scope simply match nothing;
87
+ * the engine reads the column and never writes it.
88
+ *
89
+ * WHY A LOCK PER DEVICE. Two policies matching one device, a device event
90
+ * and the sweep, or two replicas of the sweep, all reconcile the SAME device
91
+ * concurrently. Every decision here is check-then-write with no transaction
92
+ * around it, so without the lock two passes both observe "no monitor yet"
93
+ * and both create — one of them then failing on the unique index, or worse
94
+ * both succeeding on different templates and each deleting the other's row
95
+ * on the next pass. The lock is keyed on the device because the device is
96
+ * what the difference is computed over.
97
+ */
98
+
99
+ /*
100
+ * Monitor writes one project's reconciliation may make before it stops and
101
+ * leaves the rest to the next sweep.
102
+ *
103
+ * A monitor create runs the whole MonitorService pipeline — billing, plan
104
+ * limits, operational status, labels, owners, SLOs, status pages, workflows,
105
+ * realtime — so five hundred of them is already minutes of work. The cap is
106
+ * per project per RUN rather than per policy, because the thing being
107
+ * protected is the project's database and its bill, and three policies each
108
+ * provisioning five hundred monitors is fifteen hundred billable rows from
109
+ * one sweep tick.
110
+ *
111
+ * A capped run loses nothing: it stamps what it did, the next sweep recomputes
112
+ * the same difference and continues, and `reconcileDevice` is idempotent.
113
+ */
114
+ export const MAX_MONITORS_PER_POLICY_SYNC: number = 500;
115
+
116
+ /*
117
+ * How many devices one update may reconcile INSIDE the request that wrote
118
+ * them.
119
+ *
120
+ * A device write is usually one device — the Settings form, a discovery
121
+ * import, a topology adoption — and reconciling it inline is what makes the
122
+ * monitor appear before the operator's next page load. A BULK write is a
123
+ * different animal: "move 1,200 devices to this site" or "archive the whole
124
+ * warehouse" matches thousands of rows, and reconciling thousands of devices
125
+ * inside an HTTP request would turn a one-statement update into an hour of
126
+ * monitor provisioning while the caller waits. Past this many devices the
127
+ * write returns immediately and the five-minute sweep converges the fleet.
128
+ */
129
+ export const MAX_INLINE_RECONCILE_DEVICES: number = 5;
130
+
131
+ /*
132
+ * The per-device lock. `Semaphore.lock` joins namespace and key with a dash,
133
+ * so the Redis key is "NetworkAlertPolicy-NetworkAlertPolicy:Device:<id>";
134
+ * the key itself is spelled in full so a `KEYS NetworkAlertPolicy:Device:*`
135
+ * during an incident finds what an operator would expect it to.
136
+ */
137
+ export const POLICY_DEVICE_LOCK_NAMESPACE: string = "NetworkAlertPolicy";
138
+
139
+ export function policyDeviceLockKey(deviceId: ObjectID | string): string {
140
+ return `NetworkAlertPolicy:Device:${deviceId.toString()}`;
141
+ }
142
+
143
+ /*
144
+ * Long enough for one device's difference (a handful of queries plus at most
145
+ * a few monitor creates), short enough that a crashed worker does not block
146
+ * a device for minutes. redis-semaphore refreshes a lock while it is held,
147
+ * so this only bounds how long a DEAD holder's lock lingers.
148
+ */
149
+ export const POLICY_DEVICE_LOCK_TIMEOUT_MS: number = 60 * 1000;
150
+
151
+ /*
152
+ * One attempt, no queueing. Every caller of reconcileDevice is either
153
+ * idempotent-and-repeated (the sweep) or fire-and-forget (a device hook), so
154
+ * a device already being reconciled by somebody else needs no second pass
155
+ * behind the first: that pass is computing the same difference from fresher
156
+ * data than this one would.
157
+ */
158
+ const POLICY_DEVICE_LOCK_ACQUIRE_ATTEMPTS: number = 1;
159
+
160
+ /*
161
+ * A syntactically valid UUID that no row can carry, used to keep a scope kind
162
+ * whose ids are ALL unusable matching nothing — see buildScopeDeviceQuery.
163
+ * The nil UUID is the natural choice: it is well-formed, and
164
+ * PrimaryGeneratedColumn("uuid") never produces it.
165
+ */
166
+ const UNMATCHABLE_ID: string = "00000000-0000-0000-0000-000000000000";
167
+
168
+ // Devices and monitors read per statement while paging a policy's fleet.
169
+ const POLICY_SYNC_PAGE_SIZE: number = 500;
170
+
171
+ /*
172
+ * The ceiling on how many devices ONE policy's forward pass will page
173
+ * through before giving up on being exhaustive. It is not a correctness
174
+ * bound — the pass is read-only until it finds a difference — but a run
175
+ * bound: an unscoped policy on a 200,000-device estate must not spend a
176
+ * whole sweep tick reading rows that are already correct. A pass that hits
177
+ * it leaves `coveredDeviceCount` alone rather than stamping a number it
178
+ * knows is short.
179
+ */
180
+ export const MAX_DEVICES_SCANNED_PER_POLICY_SYNC: number = LIMIT_PER_PROJECT;
181
+
182
+ /*
183
+ * Everything one reconciliation run shares.
184
+ *
185
+ * A "run" is one sweep tick's work for one project, or one device write's
186
+ * inline work, or one policy save. Holding the project's policies, its
187
+ * templates and its plan verdict here is what stops a 500-device sync from
188
+ * asking the same three questions 500 times — and, more importantly, what
189
+ * makes "stop at the first plan exception" possible at all: the verdict is
190
+ * remembered, so a project whose plan does not allow another monitor
191
+ * produces ONE message on its policies instead of 500 identical failures.
192
+ */
193
+ export interface PolicyRunContext {
194
+ projectId: ObjectID;
195
+ // Loaded lazily, once, and only when something actually needs them.
196
+ policies: Array<NetworkAlertPolicy> | null;
197
+ templatesById: Map<string, MonitorTemplate | null>;
198
+ /*
199
+ * The plan's answer to "may this project have another monitor", and
200
+ * whether it has been asked yet. `planException` being set is terminal for
201
+ * the run: `isStopped` goes with it.
202
+ */
203
+ planChecked: boolean;
204
+ planException: string | null;
205
+ isStopped: boolean;
206
+ // Writes made, against MAX_MONITORS_PER_POLICY_SYNC.
207
+ monitorBudget: number;
208
+ monitorsWritten: number;
209
+ monitorsCreated: number;
210
+ monitorsAdopted: number;
211
+ monitorsDeleted: number;
212
+ monitorsPaused: number;
213
+ // True once the budget stopped the run short of a complete difference.
214
+ isTruncated: boolean;
215
+ /*
216
+ * Non-plan failures, verbatim and in order. The first one is what reaches
217
+ * `lastSyncError`; the rest are logged. Bounded so a pathological run
218
+ * cannot grow this without limit.
219
+ */
220
+ failures: Array<string>;
221
+ }
222
+
223
+ const MAX_RECORDED_FAILURES_PER_RUN: number = 20;
224
+
225
+ /*
226
+ * What a policy's monitors are keyed by, everywhere in this file: the policy
227
+ * that owns them AND the template that policy names right now. A monitor
228
+ * carrying the policy's id but a template the policy no longer names is a
229
+ * leftover from the policy's previous template and is removed — that is how
230
+ * "re-point a policy at a different template" re-clones the fleet.
231
+ */
232
+ function ownershipKey(
233
+ policyId: ObjectID | string,
234
+ monitorTemplateId: ObjectID | string,
235
+ ): string {
236
+ return `${policyId.toString()}:${monitorTemplateId.toString()}`;
237
+ }
238
+
239
+ /*
240
+ * The scope columns the matcher needs, plus the columns that decide whether a
241
+ * device is provisionable at all. `labels` is a relation, so it has to be
242
+ * asked for by name or it arrives undefined and every label-scoped policy
243
+ * silently matches nothing.
244
+ */
245
+ const RECONCILE_DEVICE_SELECT: Select<NetworkDevice> = {
246
+ _id: true,
247
+ projectId: true,
248
+ name: true,
249
+ hostname: true,
250
+ siteId: true,
251
+ networkDeviceRoleId: true,
252
+ isArchived: true,
253
+ monitoringMethod: true,
254
+ probeId: true,
255
+ labels: {
256
+ _id: true,
257
+ },
258
+ };
259
+
260
+ class NetworkAlertPolicyEngineServiceClass {
261
+ /*
262
+ * A fresh run. `monitorBudget` is per project per run — see
263
+ * MAX_MONITORS_PER_POLICY_SYNC.
264
+ */
265
+ public createRunContext(
266
+ projectId: ObjectID,
267
+ monitorBudget: number = MAX_MONITORS_PER_POLICY_SYNC,
268
+ ): PolicyRunContext {
269
+ return {
270
+ projectId: projectId,
271
+ policies: null,
272
+ templatesById: new Map<string, MonitorTemplate | null>(),
273
+ planChecked: false,
274
+ planException: null,
275
+ isStopped: false,
276
+ monitorBudget: monitorBudget,
277
+ monitorsWritten: 0,
278
+ monitorsCreated: 0,
279
+ monitorsAdopted: 0,
280
+ monitorsDeleted: 0,
281
+ monitorsPaused: 0,
282
+ isTruncated: false,
283
+ failures: [],
284
+ };
285
+ }
286
+
287
+ /**
288
+ * THE mutation path. Brings one device's policy-owned monitors in line
289
+ * with the project's policies, under the device's own Redis lock.
290
+ *
291
+ * Never throws for an ordinary failure: a device create must not fail
292
+ * because a template was deleted or Redis is down. Failures are recorded
293
+ * on the run context (and reach `lastSyncError` when the caller is a
294
+ * policy sync); the next sweep recomputes the same difference.
295
+ */
296
+ @CaptureSpan()
297
+ public async reconcileDevice(data: {
298
+ projectId: ObjectID;
299
+ deviceId: ObjectID;
300
+ context?: PolicyRunContext | undefined;
301
+ }): Promise<PolicyRunContext> {
302
+ const context: PolicyRunContext =
303
+ data.context || this.createRunContext(data.projectId);
304
+
305
+ if (context.isStopped) {
306
+ return context;
307
+ }
308
+
309
+ let mutex: SemaphoreMutex | null = null;
310
+
311
+ try {
312
+ mutex = await Semaphore.lock({
313
+ key: policyDeviceLockKey(data.deviceId),
314
+ namespace: POLICY_DEVICE_LOCK_NAMESPACE,
315
+ lockTimeout: POLICY_DEVICE_LOCK_TIMEOUT_MS,
316
+ acquireAttemptsLimit: POLICY_DEVICE_LOCK_ACQUIRE_ATTEMPTS,
317
+ });
318
+ } catch (error) {
319
+ /*
320
+ * Somebody else is reconciling this device right now (or Redis is
321
+ * unavailable). Both are safely skippable: the other pass computes the
322
+ * same difference from fresher data, and the sweep runs again in five
323
+ * minutes. Debug, not error — under a busy sweep this is the normal
324
+ * outcome of a device event landing mid-pass.
325
+ */
326
+ logger.debug(
327
+ `NetworkAlertPolicy engine: could not lock device ${data.deviceId.toString()} for reconciliation; another pass holds it (or Redis is unavailable): ${error}`,
328
+ );
329
+
330
+ return context;
331
+ }
332
+
333
+ try {
334
+ await this.reconcileDeviceUnderLock({
335
+ projectId: data.projectId,
336
+ deviceId: data.deviceId,
337
+ context: context,
338
+ });
339
+ } catch (error) {
340
+ this.recordFailure(
341
+ context,
342
+ `Could not reconcile device ${data.deviceId.toString()}: ${error}`,
343
+ );
344
+ } finally {
345
+ try {
346
+ await Semaphore.release(mutex);
347
+ } catch (error) {
348
+ logger.error(
349
+ `NetworkAlertPolicy engine: failed to release the lock on device ${data.deviceId.toString()}: ${error}`,
350
+ );
351
+ }
352
+ }
353
+
354
+ return context;
355
+ }
356
+
357
+ /**
358
+ * Reconcile a handful of devices in one run — what a device write does
359
+ * inline. Callers that may have written more than
360
+ * MAX_INLINE_RECONCILE_DEVICES devices must not call this; the sweep is
361
+ * for them.
362
+ */
363
+ @CaptureSpan()
364
+ public async reconcileDevices(data: {
365
+ projectId: ObjectID;
366
+ deviceIds: Array<ObjectID>;
367
+ context?: PolicyRunContext | undefined;
368
+ }): Promise<PolicyRunContext> {
369
+ const context: PolicyRunContext =
370
+ data.context || this.createRunContext(data.projectId);
371
+
372
+ for (const deviceId of data.deviceIds) {
373
+ if (context.isStopped) {
374
+ break;
375
+ }
376
+
377
+ await this.reconcileDevice({
378
+ projectId: data.projectId,
379
+ deviceId: deviceId,
380
+ context: context,
381
+ });
382
+ }
383
+
384
+ return context;
385
+ }
386
+
387
+ private async reconcileDeviceUnderLock(data: {
388
+ projectId: ObjectID;
389
+ deviceId: ObjectID;
390
+ context: PolicyRunContext;
391
+ }): Promise<void> {
392
+ const context: PolicyRunContext = data.context;
393
+
394
+ /*
395
+ * Read fresh under the lock, never from the caller's snapshot: the whole
396
+ * point of the lock is that the difference is computed from the state
397
+ * that is true right now.
398
+ */
399
+ const device: NetworkDevice | null = await NetworkDeviceService.findOneBy({
400
+ query: {
401
+ _id: data.deviceId,
402
+ projectId: data.projectId,
403
+ },
404
+ select: RECONCILE_DEVICE_SELECT,
405
+ props: {
406
+ isRoot: true,
407
+ },
408
+ });
409
+
410
+ const actualMonitors: Array<Monitor> = await MonitorService.findBy({
411
+ query: {
412
+ projectId: data.projectId,
413
+ autoProvisionedNetworkDeviceId: data.deviceId,
414
+ // The second half of "a policy made this". See the file header.
415
+ networkAlertPolicyId: QueryHelper.notNull(),
416
+ },
417
+ select: {
418
+ _id: true,
419
+ networkAlertPolicyId: true,
420
+ monitorTemplateId: true,
421
+ disableActiveMonitoring: true,
422
+ },
423
+ limit: LIMIT_MAX,
424
+ skip: 0,
425
+ props: {
426
+ isRoot: true,
427
+ },
428
+ });
429
+
430
+ /*
431
+ * A device that is gone — or that never was in this project — keeps no
432
+ * policy monitors.
433
+ *
434
+ * NetworkDeviceService.onBeforeDelete removes them before the device row
435
+ * goes, so this branch should be unreachable through the ordinary path;
436
+ * and for a HARD delete Monitor's RESTRICT foreign key would refuse
437
+ * outright. What makes it reachable at all is a SOFT delete, which
438
+ * stamps deletedAt without touching the foreign key: the device stops
439
+ * being readable and its monitors are left behind. The cleanup is scoped
440
+ * to the same (project, device) pair the monitors were read under, so it
441
+ * can never reach further than the device that vanished.
442
+ */
443
+ if (!device) {
444
+ await this.deleteMonitors({
445
+ projectId: data.projectId,
446
+ monitors: actualMonitors,
447
+ context: context,
448
+ reason: `device ${data.deviceId.toString()} no longer exists`,
449
+ });
450
+
451
+ return;
452
+ }
453
+
454
+ const isProvisionable: boolean = this.isDeviceProvisionable(device);
455
+
456
+ /*
457
+ * Not provisionable: archived, monitor-backed, or without a probe.
458
+ * EVERY policy-owned monitor goes, including a paused one belonging to a
459
+ * disabled policy — a device whose health is now a bound monitor's has
460
+ * no use for a Network Device monitor at all, and leaving one behind
461
+ * would keep billing for a monitor nothing can ever feed. Turning the
462
+ * device back into a probe-polled one re-provisions it, because the
463
+ * method write reconciles it again.
464
+ */
465
+ if (!isProvisionable) {
466
+ await this.deleteMonitors({
467
+ projectId: data.projectId,
468
+ monitors: actualMonitors,
469
+ context: context,
470
+ reason: this.describeUnprovisionable(device),
471
+ });
472
+
473
+ return;
474
+ }
475
+
476
+ const policies: Array<NetworkAlertPolicy> =
477
+ await this.getProjectPolicies(context);
478
+
479
+ const policiesById: Map<string, NetworkAlertPolicy> = new Map<
480
+ string,
481
+ NetworkAlertPolicy
482
+ >();
483
+
484
+ for (const policy of policies) {
485
+ if (policy.id) {
486
+ policiesById.set(policy.id.toString(), policy);
487
+ }
488
+ }
489
+
490
+ const deviceScope: {
491
+ siteId: string | null;
492
+ networkDeviceRoleId: string | null;
493
+ labelIds: Array<string>;
494
+ } = this.toScopeDevice(device);
495
+
496
+ // DESIRED: enabled, template-carrying policies whose scope covers this device.
497
+ const desiredByOwnershipKey: Map<
498
+ string,
499
+ { policy: NetworkAlertPolicy; monitorTemplateId: ObjectID }
500
+ > = new Map<
501
+ string,
502
+ { policy: NetworkAlertPolicy; monitorTemplateId: ObjectID }
503
+ >();
504
+
505
+ for (const policy of policies) {
506
+ if (!policy.id || !policy.isEnabled || !policy.monitorTemplateId) {
507
+ continue;
508
+ }
509
+
510
+ if (
511
+ !NetworkAlertPolicyScopeUtil.matchesDevice(policy.scope, deviceScope)
512
+ ) {
513
+ continue;
514
+ }
515
+
516
+ desiredByOwnershipKey.set(
517
+ ownershipKey(policy.id, policy.monitorTemplateId),
518
+ {
519
+ policy: policy,
520
+ monitorTemplateId: policy.monitorTemplateId,
521
+ },
522
+ );
523
+ }
524
+
525
+ const satisfiedOwnershipKeys: Set<string> = new Set<string>();
526
+ const monitorsToDelete: Array<Monitor> = [];
527
+ const monitorsToPause: Array<Monitor> = [];
528
+
529
+ for (const monitor of actualMonitors) {
530
+ const policyId: ObjectID | undefined = monitor.networkAlertPolicyId;
531
+
532
+ if (!policyId) {
533
+ // The query asked for NOT NULL; belt and braces against a stale row.
534
+ continue;
535
+ }
536
+
537
+ const owner: NetworkAlertPolicy | undefined = policiesById.get(
538
+ policyId.toString(),
539
+ );
540
+
541
+ /*
542
+ * The owning policy is gone (deleted, and this monitor outlived the
543
+ * delete's own cleanup). Nothing owns it any more, and nobody will
544
+ * ever tear it down if this pass does not.
545
+ */
546
+ if (!owner) {
547
+ monitorsToDelete.push(monitor);
548
+ continue;
549
+ }
550
+
551
+ const key: string = monitor.monitorTemplateId
552
+ ? ownershipKey(policyId, monitor.monitorTemplateId)
553
+ : "";
554
+
555
+ if (key && desiredByOwnershipKey.has(key)) {
556
+ satisfiedOwnershipKeys.add(key);
557
+ continue;
558
+ }
559
+
560
+ /*
561
+ * A DISABLED policy's monitors survive. Disabling is a pause, not a
562
+ * teardown — the operator's way to stop alerting on a fleet for an
563
+ * afternoon without losing every monitor's incident history and
564
+ * without re-provisioning (and re-billing) hundreds of rows when they
565
+ * switch it back on. What disabling DOES do is stop the monitors
566
+ * running, which is `disableActiveMonitoring` (honoured by the walk
567
+ * fan-out), asserted here so a monitor that missed the transition
568
+ * write still ends up paused.
569
+ *
570
+ * A template-less policy — only reachable through the FK's SET NULL
571
+ * backstop, since the template delete guard refuses the delete — is
572
+ * treated identically: there is nothing to provision from, so nothing
573
+ * is provisioned and nothing is destroyed.
574
+ */
575
+ const isPausedOwner: boolean =
576
+ !owner.isEnabled || !owner.monitorTemplateId;
577
+
578
+ const stillMatchesOwnerScope: boolean =
579
+ NetworkAlertPolicyScopeUtil.matchesDevice(owner.scope, deviceScope);
580
+
581
+ const carriesOwnerTemplate: boolean = Boolean(
582
+ owner.monitorTemplateId &&
583
+ monitor.monitorTemplateId &&
584
+ owner.monitorTemplateId.toString() ===
585
+ monitor.monitorTemplateId.toString(),
586
+ );
587
+
588
+ if (
589
+ isPausedOwner &&
590
+ stillMatchesOwnerScope &&
591
+ (carriesOwnerTemplate || !owner.monitorTemplateId)
592
+ ) {
593
+ if (!monitor.disableActiveMonitoring) {
594
+ monitorsToPause.push(monitor);
595
+ }
596
+
597
+ continue;
598
+ }
599
+
600
+ /*
601
+ * What is left is a monitor this policy no longer wants on this
602
+ * device: the scope shrank away from it, or the policy was re-pointed
603
+ * at a different template and this row is the old template's. Either
604
+ * way it is stamped with THIS policy's id, which is the only thing
605
+ * that makes it safe to delete.
606
+ */
607
+ monitorsToDelete.push(monitor);
608
+ }
609
+
610
+ await this.deleteMonitors({
611
+ projectId: data.projectId,
612
+ monitors: monitorsToDelete,
613
+ context: context,
614
+ reason: `device ${device.id?.toString()} is no longer covered by the owning policy`,
615
+ });
616
+
617
+ await this.pauseMonitors({
618
+ projectId: data.projectId,
619
+ monitors: monitorsToPause,
620
+ context: context,
621
+ });
622
+
623
+ for (const desired of desiredByOwnershipKey.values()) {
624
+ if (context.isStopped) {
625
+ return;
626
+ }
627
+
628
+ const key: string = ownershipKey(
629
+ desired.policy.id!,
630
+ desired.monitorTemplateId,
631
+ );
632
+
633
+ if (satisfiedOwnershipKeys.has(key)) {
634
+ continue;
635
+ }
636
+
637
+ await this.provisionMonitor({
638
+ context: context,
639
+ device: device,
640
+ policy: desired.policy,
641
+ monitorTemplateId: desired.monitorTemplateId,
642
+ });
643
+ }
644
+ }
645
+
646
+ /*
647
+ * Give one device one policy's monitor: adopt the (device, template)
648
+ * monitor that already exists without an owner, or create it.
649
+ *
650
+ * ADOPTION, not duplication, and the reason is Monitor's partial unique
651
+ * index on (autoProvisionedNetworkDeviceId, monitorTemplateId). An
652
+ * auto-import rule provisioned from the same template, or a person built a
653
+ * monitor from it by hand, and that row already occupies the pair. A
654
+ * create would fail on the index on this pass and on every pass after it,
655
+ * so the policy would report a failure forever while a perfectly good
656
+ * monitor for exactly the right thing sat next to it. Stamping the policy
657
+ * id onto it is what "this policy covers this device" actually means.
658
+ */
659
+ private async provisionMonitor(data: {
660
+ context: PolicyRunContext;
661
+ device: NetworkDevice;
662
+ policy: NetworkAlertPolicy;
663
+ monitorTemplateId: ObjectID;
664
+ }): Promise<void> {
665
+ const context: PolicyRunContext = data.context;
666
+
667
+ /*
668
+ * Peeked, not consumed. Nothing has been written yet, and the two ways
669
+ * this method can return without writing — an unusable template, a plan
670
+ * refusal — must not spend a unit of a budget they never used.
671
+ */
672
+ if (!this.hasMonitorBudget(context)) {
673
+ return;
674
+ }
675
+
676
+ const unowned: Monitor | null = await MonitorService.findOneBy({
677
+ query: {
678
+ projectId: context.projectId,
679
+ autoProvisionedNetworkDeviceId: data.device.id!,
680
+ monitorTemplateId: data.monitorTemplateId,
681
+ networkAlertPolicyId: QueryHelper.isNull(),
682
+ },
683
+ select: {
684
+ _id: true,
685
+ },
686
+ props: {
687
+ isRoot: true,
688
+ },
689
+ });
690
+
691
+ if (unowned && unowned.id) {
692
+ if (!this.takeMonitorBudget(context)) {
693
+ return;
694
+ }
695
+
696
+ await this.adoptMonitor({
697
+ context: context,
698
+ monitorId: unowned.id,
699
+ policy: data.policy,
700
+ });
701
+
702
+ return;
703
+ }
704
+
705
+ const template: MonitorTemplate | null = await this.getMonitorTemplate({
706
+ context: context,
707
+ monitorTemplateId: data.monitorTemplateId,
708
+ });
709
+
710
+ if (!template) {
711
+ this.recordFailure(
712
+ context,
713
+ `Monitor template ${data.monitorTemplateId.toString()} is missing or is not a Network Device template, so policy "${data.policy.name || data.policy.id?.toString()}" could not provision a monitor.`,
714
+ );
715
+
716
+ return;
717
+ }
718
+
719
+ /*
720
+ * Asked once per run, BEFORE the first create, so a project whose plan
721
+ * cannot hold another monitor gets one sentence on its policies rather
722
+ * than one failure per device.
723
+ */
724
+ if (await this.stopIfPlanRefusesAnotherMonitor(context)) {
725
+ return;
726
+ }
727
+
728
+ if (!this.takeMonitorBudget(context)) {
729
+ return;
730
+ }
731
+
732
+ try {
733
+ const monitor: Monitor = NetworkDeviceMonitorTemplateUtil.buildMonitor({
734
+ template: template,
735
+ networkDevice: data.device,
736
+ });
737
+
738
+ /*
739
+ * The stamp that makes this monitor the policy's. Written on the
740
+ * create rather than in a follow-up update because a monitor that
741
+ * exists for a moment without its owner is a monitor the next pass
742
+ * would ADOPT — harmless — but also one a concurrent pass of a
743
+ * different policy could adopt, which would not be.
744
+ */
745
+ monitor.networkAlertPolicyId = new ObjectID(data.policy.id!.toString());
746
+
747
+ await MonitorService.create({
748
+ data: monitor,
749
+ props: {
750
+ isRoot: true,
751
+ tenantId: context.projectId,
752
+ },
753
+ });
754
+
755
+ context.monitorsCreated++;
756
+ } catch (error) {
757
+ /*
758
+ * A create can fail for two very different reasons, and telling them
759
+ * apart is the whole of prerequisite 5.
760
+ *
761
+ * If the PLAN now refuses another monitor, every remaining create in
762
+ * this run would fail identically: stop, and let the one message reach
763
+ * every policy the run stamps. The verdict is re-asked rather than
764
+ * pattern-matched out of the error text, so the classification cannot
765
+ * drift when MonitorService rewords its refusal.
766
+ *
767
+ * Otherwise this is one device's problem — a lost race on the unique
768
+ * index, a name collision, a template that stopped validating — so
769
+ * record it and carry on with the rest of the fleet.
770
+ */
771
+ if (await this.stopIfPlanRefusesAnotherMonitor(context, true)) {
772
+ return;
773
+ }
774
+
775
+ const adopted: boolean = await this.adoptAfterCreateRace({
776
+ context: context,
777
+ device: data.device,
778
+ policy: data.policy,
779
+ monitorTemplateId: data.monitorTemplateId,
780
+ });
781
+
782
+ if (adopted) {
783
+ return;
784
+ }
785
+
786
+ this.recordFailure(
787
+ context,
788
+ `Could not provision a monitor for device ${data.device.id?.toString()} from policy "${data.policy.name || data.policy.id?.toString()}": ${error}`,
789
+ );
790
+ }
791
+ }
792
+
793
+ /*
794
+ * The unique index is the final race backstop: if another writer created
795
+ * the (device, template) monitor between our look and our create, the row
796
+ * that exists is the one the policy wanted. Claim it if it is unowned,
797
+ * count it as satisfied if it is already ours, and leave it alone if some
798
+ * other policy got there first (which the one-policy-per-template rule
799
+ * makes unreachable, but which must never turn into a delete).
800
+ */
801
+ private async adoptAfterCreateRace(data: {
802
+ context: PolicyRunContext;
803
+ device: NetworkDevice;
804
+ policy: NetworkAlertPolicy;
805
+ monitorTemplateId: ObjectID;
806
+ }): Promise<boolean> {
807
+ const existing: Monitor | null = await MonitorService.findOneBy({
808
+ query: {
809
+ projectId: data.context.projectId,
810
+ autoProvisionedNetworkDeviceId: data.device.id!,
811
+ monitorTemplateId: data.monitorTemplateId,
812
+ },
813
+ select: {
814
+ _id: true,
815
+ networkAlertPolicyId: true,
816
+ },
817
+ props: {
818
+ isRoot: true,
819
+ },
820
+ });
821
+
822
+ if (!existing || !existing.id) {
823
+ return false;
824
+ }
825
+
826
+ if (!existing.networkAlertPolicyId) {
827
+ await this.adoptMonitor({
828
+ context: data.context,
829
+ monitorId: existing.id,
830
+ policy: data.policy,
831
+ });
832
+
833
+ return true;
834
+ }
835
+
836
+ return (
837
+ existing.networkAlertPolicyId.toString() === data.policy.id!.toString()
838
+ );
839
+ }
840
+
841
+ private async adoptMonitor(data: {
842
+ context: PolicyRunContext;
843
+ monitorId: ObjectID;
844
+ policy: NetworkAlertPolicy;
845
+ }): Promise<void> {
846
+ /*
847
+ * A provenance stamp, not an operational change: no hooks, no workflow,
848
+ * no realtime event, no audit row. The monitor keeps doing exactly what
849
+ * it was doing; all that changes is who is answerable for it.
850
+ */
851
+ await MonitorService.updateColumnsByIdWithoutHooks({
852
+ id: data.monitorId,
853
+ data: {
854
+ networkAlertPolicyId: new ObjectID(data.policy.id!.toString()),
855
+ },
856
+ });
857
+
858
+ data.context.monitorsAdopted++;
859
+
860
+ logger.debug(
861
+ `NetworkAlertPolicy engine: adopted existing monitor ${data.monitorId.toString()} into policy "${data.policy.name || data.policy.id?.toString()}" rather than creating a duplicate.`,
862
+ );
863
+ }
864
+
865
+ /**
866
+ * Bring one policy's whole fleet in line: every device its scope matches
867
+ * gets a monitor, and every monitor it owns whose device no longer matches
868
+ * loses one. This is what the five-minute sweep runs, and what a policy
869
+ * save runs for the policy that was saved.
870
+ *
871
+ * Stamps the four engine columns the settings table reads, so a policy
872
+ * that has been failing since Tuesday says so where the operator is.
873
+ */
874
+ @CaptureSpan()
875
+ public async syncPolicy(data: {
876
+ policyId: ObjectID;
877
+ context?: PolicyRunContext | undefined;
878
+ /*
879
+ * True when the caller has just re-pointed the policy at a DIFFERENT
880
+ * template, so a clean complete pass leaves every monitor the policy
881
+ * owns freshly cloned from the template it names now — which is exactly
882
+ * what `templateSyncedAt` claims. Never set on an ordinary sweep: a
883
+ * sweep that changes nothing has not re-synced anything from a template.
884
+ */
885
+ stampTemplateSyncedOnCleanPass?: boolean | undefined;
886
+ }): Promise<PolicyRunContext | null> {
887
+ const policy: NetworkAlertPolicy | null =
888
+ await NetworkAlertPolicyService.findOneBy({
889
+ query: {
890
+ _id: data.policyId,
891
+ },
892
+ select: {
893
+ _id: true,
894
+ projectId: true,
895
+ name: true,
896
+ isEnabled: true,
897
+ monitorTemplateId: true,
898
+ scope: true,
899
+ },
900
+ props: {
901
+ isRoot: true,
902
+ },
903
+ });
904
+
905
+ if (!policy || !policy.id || !policy.projectId) {
906
+ // Deleted between the hook and here; its monitors went with it.
907
+ return null;
908
+ }
909
+
910
+ /*
911
+ * A run context carries a project's monitor budget and its plan verdict,
912
+ * so using one that belongs to a different project would spend the wrong
913
+ * project's budget and — worse — could read a plan refusal as this
914
+ * project's. The sweep groups policies by project, so this only fires on
915
+ * a caller mistake; it is corrected rather than trusted.
916
+ */
917
+ const context: PolicyRunContext =
918
+ data.context &&
919
+ data.context.projectId.toString() === policy.projectId.toString()
920
+ ? data.context
921
+ : this.createRunContext(policy.projectId);
922
+
923
+ /*
924
+ * A disabled or template-less policy provisions nothing and tears down
925
+ * nothing (see the paused branch in reconcileDeviceUnderLock). Its
926
+ * monitors are paused by the transition that disabled it, and stamping
927
+ * lastSyncAt here is honest: the engine did look, and the answer was
928
+ * "nothing to do".
929
+ */
930
+ if (!policy.isEnabled || !policy.monitorTemplateId) {
931
+ await this.stampPolicy({
932
+ policyId: policy.id,
933
+ lastSyncAt: OneUptimeDate.getCurrentDate(),
934
+ lastSyncError: null,
935
+ });
936
+
937
+ return context;
938
+ }
939
+
940
+ const scannedDeviceIds: Set<string> = new Set<string>();
941
+ let coveredDeviceCount: number = 0;
942
+ let isScanComplete: boolean = true;
943
+
944
+ try {
945
+ const forwardPass: { coveredDeviceCount: number; isComplete: boolean } =
946
+ await this.provisionForMatchingDevices({
947
+ policy: policy,
948
+ context: context,
949
+ scannedDeviceIds: scannedDeviceIds,
950
+ });
951
+
952
+ coveredDeviceCount = forwardPass.coveredDeviceCount;
953
+ isScanComplete = forwardPass.isComplete;
954
+
955
+ await this.reconcileOrphanedPolicyMonitors({
956
+ policy: policy,
957
+ context: context,
958
+ confirmedDeviceIds: isScanComplete ? scannedDeviceIds : null,
959
+ });
960
+ } catch (error) {
961
+ this.recordFailure(
962
+ context,
963
+ `Could not sync policy "${policy.name || policy.id.toString()}": ${error}`,
964
+ );
965
+ }
966
+
967
+ const isCleanCompletePass: boolean =
968
+ isScanComplete &&
969
+ !context.isTruncated &&
970
+ !context.isStopped &&
971
+ context.failures.length === 0;
972
+
973
+ await this.stampPolicy({
974
+ policyId: policy.id,
975
+ lastSyncAt: OneUptimeDate.getCurrentDate(),
976
+ lastSyncError: context.planException || context.failures[0] || null,
977
+ /*
978
+ * Only from a pass that actually counted the whole fleet. A truncated
979
+ * pass knows its number is short, and a short number beside a scope
980
+ * sentence reads as "the policy lost devices", which is worse than the
981
+ * previous pass's number staying put for five minutes.
982
+ */
983
+ coveredDeviceCount: isScanComplete ? coveredDeviceCount : undefined,
984
+ /*
985
+ * ...and only when the pass rebuilt the fleet from a template the
986
+ * policy had just been re-pointed at, with nothing adopted (an adopted
987
+ * monitor was built by somebody else and its criteria are not this
988
+ * template's). Pushing a template EDIT onto an existing fleet is
989
+ * MonitorTemplateService.syncLinkedMonitors' job; it stamps this
990
+ * column through onMonitorTemplateSynced.
991
+ */
992
+ templateSyncedAt:
993
+ data.stampTemplateSyncedOnCleanPass &&
994
+ isCleanCompletePass &&
995
+ context.monitorsAdopted === 0
996
+ ? OneUptimeDate.getCurrentDate()
997
+ : undefined,
998
+ });
999
+
1000
+ return context;
1001
+ }
1002
+
1003
+ /*
1004
+ * Forward pass: every device the scope matches, paged by `_id`.
1005
+ *
1006
+ * `_id` keyset paging rather than skip/offset because the pass WRITES —
1007
+ * provisioning a monitor does not move a device row, but archiving one
1008
+ * during the pass does remove it from the result set, and an offset page
1009
+ * then steps over a device that was never looked at. A keyset resumes from
1010
+ * the last id seen, so a row leaving the set behind the cursor costs
1011
+ * nothing.
1012
+ *
1013
+ * The monitors for a whole page are read in ONE query, so a fleet that is
1014
+ * already correct — the overwhelmingly common case, five minutes after the
1015
+ * last sweep — costs two statements per five hundred devices and takes no
1016
+ * per-device lock at all.
1017
+ */
1018
+ private async provisionForMatchingDevices(data: {
1019
+ policy: NetworkAlertPolicy;
1020
+ context: PolicyRunContext;
1021
+ scannedDeviceIds: Set<string>;
1022
+ }): Promise<{ coveredDeviceCount: number; isComplete: boolean }> {
1023
+ const monitorTemplateId: ObjectID = data.policy.monitorTemplateId!;
1024
+ const deviceQuery: Query<NetworkDevice> = this.buildScopeDeviceQuery({
1025
+ projectId: data.context.projectId,
1026
+ scope: data.policy.scope,
1027
+ });
1028
+
1029
+ let cursor: ObjectID | null = null;
1030
+ let coveredDeviceCount: number = 0;
1031
+ let scanned: number = 0;
1032
+
1033
+ for (;;) {
1034
+ const devices: Array<NetworkDevice> = await NetworkDeviceService.findBy({
1035
+ query: cursor
1036
+ ? { ...deviceQuery, _id: QueryHelper.greaterThan(cursor) }
1037
+ : deviceQuery,
1038
+ select: RECONCILE_DEVICE_SELECT,
1039
+ sort: {
1040
+ _id: SortOrder.Ascending,
1041
+ },
1042
+ limit: POLICY_SYNC_PAGE_SIZE,
1043
+ skip: 0,
1044
+ props: {
1045
+ isRoot: true,
1046
+ },
1047
+ });
1048
+
1049
+ if (devices.length === 0) {
1050
+ return { coveredDeviceCount: coveredDeviceCount, isComplete: true };
1051
+ }
1052
+
1053
+ cursor = devices[devices.length - 1]!.id;
1054
+ scanned += devices.length;
1055
+
1056
+ /*
1057
+ * `monitoringMethod` is free text whose NULL, "" and legacy "SNMP" all
1058
+ * mean Probe, so it cannot be filtered in SQL without writing a
1059
+ * predicate that would silently drop every pre-ping-first row. Filtered
1060
+ * here instead, over one page at a time.
1061
+ */
1062
+ const provisionableDevices: Array<NetworkDevice> = devices.filter(
1063
+ (device: NetworkDevice): boolean => {
1064
+ return this.isDeviceProvisionable(device);
1065
+ },
1066
+ );
1067
+
1068
+ coveredDeviceCount += provisionableDevices.length;
1069
+
1070
+ for (const device of provisionableDevices) {
1071
+ if (device.id) {
1072
+ data.scannedDeviceIds.add(device.id.toString());
1073
+ }
1074
+ }
1075
+
1076
+ const deviceIdsMissingMonitor: Array<ObjectID> =
1077
+ await this.findDevicesMissingPolicyMonitor({
1078
+ projectId: data.context.projectId,
1079
+ policyId: data.policy.id!,
1080
+ monitorTemplateId: monitorTemplateId,
1081
+ devices: provisionableDevices,
1082
+ });
1083
+
1084
+ for (const deviceId of deviceIdsMissingMonitor) {
1085
+ if (data.context.isStopped || data.context.isTruncated) {
1086
+ return {
1087
+ coveredDeviceCount: coveredDeviceCount,
1088
+ isComplete: false,
1089
+ };
1090
+ }
1091
+
1092
+ await this.reconcileDevice({
1093
+ projectId: data.context.projectId,
1094
+ deviceId: deviceId,
1095
+ context: data.context,
1096
+ });
1097
+ }
1098
+
1099
+ if (devices.length < POLICY_SYNC_PAGE_SIZE) {
1100
+ return { coveredDeviceCount: coveredDeviceCount, isComplete: true };
1101
+ }
1102
+
1103
+ if (scanned >= MAX_DEVICES_SCANNED_PER_POLICY_SYNC) {
1104
+ logger.debug(
1105
+ `NetworkAlertPolicy engine: policy ${data.policy.id?.toString()} stopped scanning after ${scanned} devices; the next sweep continues.`,
1106
+ );
1107
+
1108
+ return { coveredDeviceCount: coveredDeviceCount, isComplete: false };
1109
+ }
1110
+ }
1111
+ }
1112
+
1113
+ /*
1114
+ * Which of these devices do NOT already carry this policy's current
1115
+ * monitor. One statement for the whole page; only the answers get the
1116
+ * per-device lock and the full difference.
1117
+ */
1118
+ private async findDevicesMissingPolicyMonitor(data: {
1119
+ projectId: ObjectID;
1120
+ policyId: ObjectID;
1121
+ monitorTemplateId: ObjectID;
1122
+ devices: Array<NetworkDevice>;
1123
+ }): Promise<Array<ObjectID>> {
1124
+ const deviceIds: Array<ObjectID> = data.devices.flatMap(
1125
+ (device: NetworkDevice): Array<ObjectID> => {
1126
+ return device.id ? [device.id] : [];
1127
+ },
1128
+ );
1129
+
1130
+ if (deviceIds.length === 0) {
1131
+ return [];
1132
+ }
1133
+
1134
+ const monitors: Array<Monitor> = await MonitorService.findBy({
1135
+ query: {
1136
+ projectId: data.projectId,
1137
+ networkAlertPolicyId: data.policyId,
1138
+ monitorTemplateId: data.monitorTemplateId,
1139
+ autoProvisionedNetworkDeviceId: QueryHelper.any(deviceIds),
1140
+ },
1141
+ select: {
1142
+ _id: true,
1143
+ autoProvisionedNetworkDeviceId: true,
1144
+ },
1145
+ limit: LIMIT_MAX,
1146
+ skip: 0,
1147
+ props: {
1148
+ isRoot: true,
1149
+ },
1150
+ });
1151
+
1152
+ const covered: Set<string> = new Set<string>();
1153
+
1154
+ for (const monitor of monitors) {
1155
+ if (monitor.autoProvisionedNetworkDeviceId) {
1156
+ covered.add(monitor.autoProvisionedNetworkDeviceId.toString());
1157
+ }
1158
+ }
1159
+
1160
+ return deviceIds.filter((deviceId: ObjectID): boolean => {
1161
+ return !covered.has(deviceId.toString());
1162
+ });
1163
+ }
1164
+
1165
+ /*
1166
+ * Reverse pass: the policy's own monitors, paged by `_id`, looking for the
1167
+ * ones whose device the forward pass did NOT confirm — a device that left
1168
+ * the scope, was archived, went monitor-backed or lost its probe. These
1169
+ * are the deletes a shrinking scope produces, and they are computed from
1170
+ * the MONITORS rather than from the devices because the set of monitors a
1171
+ * policy owns is bounded by what it provisioned, while "every device that
1172
+ * no longer matches" is the whole estate.
1173
+ *
1174
+ * `confirmedDeviceIds` is the forward pass's answer, and it is only
1175
+ * trustworthy when that pass was exhaustive. When it was not, every
1176
+ * monitor's device is re-evaluated instead — slower, and correct.
1177
+ */
1178
+ private async reconcileOrphanedPolicyMonitors(data: {
1179
+ policy: NetworkAlertPolicy;
1180
+ context: PolicyRunContext;
1181
+ confirmedDeviceIds: Set<string> | null;
1182
+ }): Promise<void> {
1183
+ let cursor: ObjectID | null = null;
1184
+
1185
+ for (;;) {
1186
+ if (data.context.isStopped || data.context.isTruncated) {
1187
+ return;
1188
+ }
1189
+
1190
+ const baseQuery: Query<Monitor> = {
1191
+ projectId: data.context.projectId,
1192
+ networkAlertPolicyId: data.policy.id!,
1193
+ };
1194
+
1195
+ const monitors: Array<Monitor> = await MonitorService.findBy({
1196
+ query: cursor
1197
+ ? { ...baseQuery, _id: QueryHelper.greaterThan(cursor) }
1198
+ : baseQuery,
1199
+ select: {
1200
+ _id: true,
1201
+ autoProvisionedNetworkDeviceId: true,
1202
+ monitorTemplateId: true,
1203
+ },
1204
+ sort: {
1205
+ _id: SortOrder.Ascending,
1206
+ },
1207
+ limit: POLICY_SYNC_PAGE_SIZE,
1208
+ skip: 0,
1209
+ props: {
1210
+ isRoot: true,
1211
+ },
1212
+ });
1213
+
1214
+ if (monitors.length === 0) {
1215
+ return;
1216
+ }
1217
+
1218
+ cursor = monitors[monitors.length - 1]!.id;
1219
+
1220
+ const deviceIdsToRecheck: Array<ObjectID> =
1221
+ await this.findMonitorDevicesNeedingRecheck({
1222
+ policy: data.policy,
1223
+ context: data.context,
1224
+ monitors: monitors,
1225
+ confirmedDeviceIds: data.confirmedDeviceIds,
1226
+ });
1227
+
1228
+ for (const deviceId of deviceIdsToRecheck) {
1229
+ if (data.context.isStopped || data.context.isTruncated) {
1230
+ return;
1231
+ }
1232
+
1233
+ await this.reconcileDevice({
1234
+ projectId: data.context.projectId,
1235
+ deviceId: deviceId,
1236
+ context: data.context,
1237
+ });
1238
+ }
1239
+
1240
+ if (monitors.length < POLICY_SYNC_PAGE_SIZE) {
1241
+ return;
1242
+ }
1243
+ }
1244
+ }
1245
+
1246
+ private async findMonitorDevicesNeedingRecheck(data: {
1247
+ policy: NetworkAlertPolicy;
1248
+ context: PolicyRunContext;
1249
+ monitors: Array<Monitor>;
1250
+ confirmedDeviceIds: Set<string> | null;
1251
+ }): Promise<Array<ObjectID>> {
1252
+ const monitorTemplateId: string = data.policy.monitorTemplateId!.toString();
1253
+ const candidates: Map<string, ObjectID> = new Map<string, ObjectID>();
1254
+
1255
+ for (const monitor of data.monitors) {
1256
+ const deviceId: ObjectID | undefined =
1257
+ monitor.autoProvisionedNetworkDeviceId;
1258
+
1259
+ if (!deviceId) {
1260
+ /*
1261
+ * A policy-stamped monitor with no device provenance cannot be
1262
+ * reconciled by device, and deleting it on a guess would destroy a
1263
+ * monitor the engine cannot prove is its own. Report it instead: it
1264
+ * takes a hand-written UPDATE to produce, and the operator should
1265
+ * see that it happened.
1266
+ */
1267
+ this.recordFailure(
1268
+ data.context,
1269
+ `Monitor ${monitor.id?.toString()} carries policy "${data.policy.name || data.policy.id?.toString()}" but no device provenance; it was left untouched.`,
1270
+ );
1271
+
1272
+ continue;
1273
+ }
1274
+
1275
+ /*
1276
+ * A monitor from the policy's PREVIOUS template always needs the full
1277
+ * per-device difference, even for a device the forward pass confirmed:
1278
+ * the forward pass only asked whether the CURRENT template's monitor
1279
+ * exists.
1280
+ */
1281
+ const carriesCurrentTemplate: boolean =
1282
+ monitor.monitorTemplateId?.toString() === monitorTemplateId;
1283
+
1284
+ if (
1285
+ carriesCurrentTemplate &&
1286
+ data.confirmedDeviceIds &&
1287
+ data.confirmedDeviceIds.has(deviceId.toString())
1288
+ ) {
1289
+ continue;
1290
+ }
1291
+
1292
+ candidates.set(deviceId.toString(), deviceId);
1293
+ }
1294
+
1295
+ if (candidates.size === 0) {
1296
+ return [];
1297
+ }
1298
+
1299
+ /*
1300
+ * When the forward pass was exhaustive its set is the whole answer:
1301
+ * anything not in it has already failed the scope or provisionability
1302
+ * test, so it goes straight to reconcileDevice without a second read.
1303
+ */
1304
+ if (data.confirmedDeviceIds) {
1305
+ return Array.from(candidates.values());
1306
+ }
1307
+
1308
+ const devices: Array<NetworkDevice> = await NetworkDeviceService.findBy({
1309
+ query: {
1310
+ projectId: data.context.projectId,
1311
+ _id: QueryHelper.any(Array.from(candidates.values())),
1312
+ },
1313
+ select: RECONCILE_DEVICE_SELECT,
1314
+ limit: LIMIT_MAX,
1315
+ skip: 0,
1316
+ props: {
1317
+ isRoot: true,
1318
+ },
1319
+ });
1320
+
1321
+ const stillCovered: Set<string> = new Set<string>();
1322
+
1323
+ for (const device of devices) {
1324
+ if (!device.id || !this.isDeviceProvisionable(device)) {
1325
+ continue;
1326
+ }
1327
+
1328
+ if (
1329
+ NetworkAlertPolicyScopeUtil.matchesDevice(
1330
+ data.policy.scope,
1331
+ this.toScopeDevice(device),
1332
+ )
1333
+ ) {
1334
+ stillCovered.add(device.id.toString());
1335
+ }
1336
+ }
1337
+
1338
+ const needsRecheck: Array<ObjectID> = [];
1339
+
1340
+ for (const [deviceIdString, deviceId] of candidates) {
1341
+ if (!stillCovered.has(deviceIdString)) {
1342
+ needsRecheck.push(deviceId);
1343
+ }
1344
+ }
1345
+
1346
+ return needsRecheck;
1347
+ }
1348
+
1349
+ /**
1350
+ * Every monitor a policy owns, removed as root, paged — what
1351
+ * NetworkAlertPolicyService.onBeforeDelete calls before the row goes.
1352
+ *
1353
+ * As ROOT, deliberately. These monitors are system-managed: the API cannot
1354
+ * create the `networkAlertPolicyId` column and cannot update it, so the
1355
+ * operator deleting the policy never chose to own them individually.
1356
+ * Making the delete depend on their monitor-delete permission would leave
1357
+ * a project with orphaned, still-billed monitors and a policy row that no
1358
+ * longer explains them.
1359
+ *
1360
+ * The SET NULL foreign key stays a backstop for a row this never reached,
1361
+ * not the mechanism: a monitor that loses its policy id that way becomes
1362
+ * an ordinary auto-provisioned monitor rather than a dangling reference.
1363
+ */
1364
+ @CaptureSpan()
1365
+ public async deleteMonitorsOwnedByPolicy(data: {
1366
+ projectId: ObjectID;
1367
+ policyId: ObjectID;
1368
+ }): Promise<number> {
1369
+ let deleted: number = 0;
1370
+ let previousFirstMonitorId: string = "";
1371
+
1372
+ for (;;) {
1373
+ const monitors: Array<Monitor> = await MonitorService.findBy({
1374
+ query: {
1375
+ projectId: data.projectId,
1376
+ networkAlertPolicyId: data.policyId,
1377
+ },
1378
+ select: {
1379
+ _id: true,
1380
+ },
1381
+ sort: {
1382
+ _id: SortOrder.Ascending,
1383
+ },
1384
+ limit: POLICY_SYNC_PAGE_SIZE,
1385
+ skip: 0,
1386
+ props: {
1387
+ isRoot: true,
1388
+ },
1389
+ });
1390
+
1391
+ if (monitors.length === 0) {
1392
+ return deleted;
1393
+ }
1394
+
1395
+ const monitorIds: Array<ObjectID> = monitors.flatMap(
1396
+ (monitor: Monitor): Array<ObjectID> => {
1397
+ return monitor.id ? [monitor.id] : [];
1398
+ },
1399
+ );
1400
+
1401
+ if (monitorIds.length === 0) {
1402
+ return deleted;
1403
+ }
1404
+
1405
+ /*
1406
+ * Deleted by id AND still keyed on the policy, so a row that changed
1407
+ * owner between the read and the delete is left alone. Always from the
1408
+ * front of the set rather than at an offset: each batch shrinks it.
1409
+ */
1410
+ await MonitorService.deleteBy({
1411
+ query: {
1412
+ _id: QueryHelper.any(monitorIds),
1413
+ projectId: data.projectId,
1414
+ networkAlertPolicyId: data.policyId,
1415
+ },
1416
+ limit: LIMIT_MAX,
1417
+ skip: 0,
1418
+ props: {
1419
+ isRoot: true,
1420
+ },
1421
+ });
1422
+
1423
+ deleted += monitorIds.length;
1424
+
1425
+ if (monitors.length < POLICY_SYNC_PAGE_SIZE) {
1426
+ return deleted;
1427
+ }
1428
+
1429
+ /*
1430
+ * The page is always read from the front, because each batch is
1431
+ * supposed to shrink the set. If the same first row comes back the set
1432
+ * did NOT shrink, and reading it again would spin a worker forever
1433
+ * rather than delete anything. Stop and say so.
1434
+ */
1435
+ const firstMonitorId: string = monitorIds[0]!.toString();
1436
+
1437
+ if (firstMonitorId === previousFirstMonitorId) {
1438
+ logger.error(
1439
+ `NetworkAlertPolicy engine: could not delete the monitors of policy ${data.policyId.toString()}; the set stopped shrinking at ${monitorIds.length} row(s).`,
1440
+ );
1441
+
1442
+ return deleted;
1443
+ }
1444
+
1445
+ previousFirstMonitorId = firstMonitorId;
1446
+ }
1447
+ }
1448
+
1449
+ /**
1450
+ * The policy-owned monitors of a set of devices, removed as root — what
1451
+ * NetworkDeviceService.onBeforeDelete calls before the devices go.
1452
+ *
1453
+ * Monitor's provenance foreign key is RESTRICT, so a policy monitor left
1454
+ * behind would make the device delete fail outright. Root for the same
1455
+ * reason as the policy delete: nobody chose these monitors individually,
1456
+ * so nobody should need permission on them individually to delete the
1457
+ * device they describe.
1458
+ */
1459
+ @CaptureSpan()
1460
+ public async deletePolicyMonitorsForDevices(data: {
1461
+ projectId: ObjectID;
1462
+ deviceIds: Array<ObjectID>;
1463
+ }): Promise<number> {
1464
+ if (data.deviceIds.length === 0) {
1465
+ return 0;
1466
+ }
1467
+
1468
+ let deleted: number = 0;
1469
+ let previousFirstMonitorId: string = "";
1470
+
1471
+ for (;;) {
1472
+ const monitors: Array<Monitor> = await MonitorService.findBy({
1473
+ query: {
1474
+ projectId: data.projectId,
1475
+ autoProvisionedNetworkDeviceId: QueryHelper.any(data.deviceIds),
1476
+ networkAlertPolicyId: QueryHelper.notNull(),
1477
+ },
1478
+ select: {
1479
+ _id: true,
1480
+ },
1481
+ sort: {
1482
+ _id: SortOrder.Ascending,
1483
+ },
1484
+ limit: POLICY_SYNC_PAGE_SIZE,
1485
+ skip: 0,
1486
+ props: {
1487
+ isRoot: true,
1488
+ },
1489
+ });
1490
+
1491
+ if (monitors.length === 0) {
1492
+ return deleted;
1493
+ }
1494
+
1495
+ const monitorIds: Array<ObjectID> = monitors.flatMap(
1496
+ (monitor: Monitor): Array<ObjectID> => {
1497
+ return monitor.id ? [monitor.id] : [];
1498
+ },
1499
+ );
1500
+
1501
+ if (monitorIds.length === 0) {
1502
+ return deleted;
1503
+ }
1504
+
1505
+ await MonitorService.deleteBy({
1506
+ query: {
1507
+ _id: QueryHelper.any(monitorIds),
1508
+ projectId: data.projectId,
1509
+ // Still policy-owned at delete time, never a hand-made monitor.
1510
+ networkAlertPolicyId: QueryHelper.notNull(),
1511
+ },
1512
+ limit: LIMIT_MAX,
1513
+ skip: 0,
1514
+ props: {
1515
+ isRoot: true,
1516
+ },
1517
+ });
1518
+
1519
+ deleted += monitorIds.length;
1520
+
1521
+ if (monitors.length < POLICY_SYNC_PAGE_SIZE) {
1522
+ return deleted;
1523
+ }
1524
+
1525
+ // Same no-progress guard as deleteMonitorsOwnedByPolicy.
1526
+ const firstMonitorId: string = monitorIds[0]!.toString();
1527
+
1528
+ if (firstMonitorId === previousFirstMonitorId) {
1529
+ logger.error(
1530
+ `NetworkAlertPolicy engine: could not delete the policy-owned monitors of ${data.deviceIds.length} device(s); the set stopped shrinking at ${monitorIds.length} row(s).`,
1531
+ );
1532
+
1533
+ return deleted;
1534
+ }
1535
+
1536
+ previousFirstMonitorId = firstMonitorId;
1537
+ }
1538
+ }
1539
+
1540
+ /**
1541
+ * Disabling a policy pauses its monitors; enabling one resumes them.
1542
+ *
1543
+ * `disableActiveMonitoring` is what the Network Device walk fan-out reads
1544
+ * before it feeds a monitor, so a paused monitor stops producing criteria
1545
+ * verdicts, incidents and alerts while keeping its history, its
1546
+ * dependencies and its id. That is what makes disabling reversible in a
1547
+ * way deleting is not.
1548
+ *
1549
+ * Paged by the flag itself: each page writes the rows it read, so the
1550
+ * matching set shrinks every pass and the loop terminates without a
1551
+ * cursor. Through updateBy, not a raw column write, so workflows, realtime
1552
+ * and audit see the pause exactly as they would an operator's.
1553
+ */
1554
+ @CaptureSpan()
1555
+ public async setPolicyMonitorsPaused(data: {
1556
+ projectId: ObjectID;
1557
+ policyId: ObjectID;
1558
+ isPaused: boolean;
1559
+ }): Promise<number> {
1560
+ let updated: number = 0;
1561
+
1562
+ for (;;) {
1563
+ const monitors: Array<Monitor> = await MonitorService.findBy({
1564
+ query: {
1565
+ projectId: data.projectId,
1566
+ networkAlertPolicyId: data.policyId,
1567
+ disableActiveMonitoring: !data.isPaused,
1568
+ },
1569
+ select: {
1570
+ _id: true,
1571
+ },
1572
+ sort: {
1573
+ _id: SortOrder.Ascending,
1574
+ },
1575
+ limit: POLICY_SYNC_PAGE_SIZE,
1576
+ skip: 0,
1577
+ props: {
1578
+ isRoot: true,
1579
+ },
1580
+ });
1581
+
1582
+ if (monitors.length === 0) {
1583
+ return updated;
1584
+ }
1585
+
1586
+ const monitorIds: Array<ObjectID> = monitors.flatMap(
1587
+ (monitor: Monitor): Array<ObjectID> => {
1588
+ return monitor.id ? [monitor.id] : [];
1589
+ },
1590
+ );
1591
+
1592
+ if (monitorIds.length === 0) {
1593
+ return updated;
1594
+ }
1595
+
1596
+ const written: number = await MonitorService.updateBy({
1597
+ query: {
1598
+ _id: QueryHelper.any(monitorIds),
1599
+ projectId: data.projectId,
1600
+ networkAlertPolicyId: data.policyId,
1601
+ },
1602
+ data: {
1603
+ disableActiveMonitoring: data.isPaused,
1604
+ },
1605
+ limit: LIMIT_MAX,
1606
+ skip: 0,
1607
+ props: {
1608
+ isRoot: true,
1609
+ },
1610
+ });
1611
+
1612
+ updated += monitorIds.length;
1613
+
1614
+ /*
1615
+ * The page is re-read on the flag, so a page that wrote nothing would
1616
+ * be read again forever. Only reachable if the write is being refused
1617
+ * or reverted by something else; stop and say so rather than spin.
1618
+ */
1619
+ if (written === 0) {
1620
+ logger.error(
1621
+ `NetworkAlertPolicy engine: could not ${
1622
+ data.isPaused ? "pause" : "resume"
1623
+ } ${monitorIds.length} monitor(s) of policy ${data.policyId.toString()}; giving up on this pass.`,
1624
+ );
1625
+
1626
+ return updated;
1627
+ }
1628
+ }
1629
+ }
1630
+
1631
+ /**
1632
+ * The template's configuration has just been pushed onto every monitor
1633
+ * cloned from it (MonitorTemplateService's explicit Sync). If a policy
1634
+ * provisions from that template, its fleet is now in step with it — which
1635
+ * is precisely what `templateSyncedAt` means to the settings table.
1636
+ *
1637
+ * Never throws: a failure to stamp a bookkeeping column must not fail the
1638
+ * sync the operator asked for.
1639
+ */
1640
+ @CaptureSpan()
1641
+ public async onMonitorTemplateSynced(data: {
1642
+ monitorTemplateId: ObjectID;
1643
+ projectId: ObjectID;
1644
+ }): Promise<void> {
1645
+ try {
1646
+ const policies: Array<NetworkAlertPolicy> =
1647
+ await NetworkAlertPolicyService.findBy({
1648
+ query: {
1649
+ projectId: data.projectId,
1650
+ monitorTemplateId: data.monitorTemplateId,
1651
+ },
1652
+ select: {
1653
+ _id: true,
1654
+ },
1655
+ limit: LIMIT_MAX,
1656
+ skip: 0,
1657
+ props: {
1658
+ isRoot: true,
1659
+ },
1660
+ });
1661
+
1662
+ for (const policy of policies) {
1663
+ if (!policy.id) {
1664
+ continue;
1665
+ }
1666
+
1667
+ await this.stampPolicy({
1668
+ policyId: policy.id,
1669
+ templateSyncedAt: OneUptimeDate.getCurrentDate(),
1670
+ });
1671
+ }
1672
+ } catch (error) {
1673
+ logger.error(
1674
+ `NetworkAlertPolicy engine: could not stamp templateSyncedAt for monitor template ${data.monitorTemplateId.toString()}: ${error}`,
1675
+ );
1676
+ }
1677
+ }
1678
+
1679
+ /*
1680
+ * The four engine columns, written without hooks.
1681
+ *
1682
+ * Not through updateOneById, and that is load-bearing rather than a
1683
+ * performance choice: NetworkAlertPolicyService.onUpdateSuccess calls the
1684
+ * engine, so a stamp made through the ordinary update path would sync the
1685
+ * policy, which would stamp it, which would sync it. `undefined` fields
1686
+ * are left out entirely, so a truncated pass does not overwrite the
1687
+ * previous pass's coveredDeviceCount with a number it knows is short.
1688
+ */
1689
+ private async stampPolicy(data: {
1690
+ policyId: ObjectID;
1691
+ lastSyncAt?: Date | undefined;
1692
+ lastSyncError?: string | null | undefined;
1693
+ coveredDeviceCount?: number | undefined;
1694
+ templateSyncedAt?: Date | undefined;
1695
+ }): Promise<void> {
1696
+ const columns: Record<string, unknown> = {};
1697
+
1698
+ if (data.lastSyncAt !== undefined) {
1699
+ columns["lastSyncAt"] = data.lastSyncAt;
1700
+ }
1701
+
1702
+ if (data.lastSyncError !== undefined) {
1703
+ columns["lastSyncError"] = data.lastSyncError;
1704
+ }
1705
+
1706
+ if (data.coveredDeviceCount !== undefined) {
1707
+ columns["coveredDeviceCount"] = data.coveredDeviceCount;
1708
+ }
1709
+
1710
+ if (data.templateSyncedAt !== undefined) {
1711
+ columns["templateSyncedAt"] = data.templateSyncedAt;
1712
+ }
1713
+
1714
+ if (Object.keys(columns).length === 0) {
1715
+ return;
1716
+ }
1717
+
1718
+ try {
1719
+ await NetworkAlertPolicyService.updateColumnsByIdWithoutHooks({
1720
+ id: data.policyId,
1721
+ data: columns as PartialEntity<NetworkAlertPolicy>,
1722
+ });
1723
+ } catch (error) {
1724
+ logger.error(
1725
+ `NetworkAlertPolicy engine: could not stamp policy ${data.policyId.toString()}: ${error}`,
1726
+ );
1727
+ }
1728
+ }
1729
+
1730
+ /*
1731
+ * The SQL half of the scope. Sites, roles and labels are plain columns (and
1732
+ * one join table), so they filter in Postgres; provisionability does not,
1733
+ * and is filtered per page by the caller.
1734
+ *
1735
+ * Ids that are not UUIDs are dropped rather than sent to Postgres, where
1736
+ * `uuid = 'not-an-id'` is a statement error that would take the whole
1737
+ * sweep down. A scope is validated at write, so this only fires for a row
1738
+ * hand-edited in the database — and "match nothing" is exactly what a
1739
+ * meaningless id should do.
1740
+ *
1741
+ * A kind whose ids are ALL unusable is not the same as a kind with no ids:
1742
+ * the empty kind matches every device, so dropping the last id of a kind
1743
+ * would silently widen the policy to the whole estate. Such a kind is
1744
+ * given an id that cannot exist instead, so it keeps matching nothing.
1745
+ */
1746
+ private buildScopeDeviceQuery(data: {
1747
+ projectId: ObjectID;
1748
+ scope: NetworkAlertPolicyScope | null | undefined;
1749
+ }): Query<NetworkDevice> {
1750
+ const scope: NetworkAlertPolicyScope =
1751
+ NetworkAlertPolicyScopeUtil.normalize(data.scope);
1752
+
1753
+ const query: Query<NetworkDevice> = {
1754
+ projectId: data.projectId,
1755
+ isArchived: false,
1756
+ // A device nothing polls can carry no monitor worth billing for.
1757
+ probeId: QueryHelper.notNull(),
1758
+ };
1759
+
1760
+ const siteIds: Array<ObjectID> | null = this.toQueryableIds(scope.siteIds);
1761
+
1762
+ if (siteIds) {
1763
+ query.siteId = QueryHelper.any(siteIds);
1764
+ }
1765
+
1766
+ const roleIds: Array<ObjectID> | null = this.toQueryableIds(
1767
+ scope.networkDeviceRoleIds,
1768
+ );
1769
+
1770
+ if (roleIds) {
1771
+ query.networkDeviceRoleId = QueryHelper.any(roleIds);
1772
+ }
1773
+
1774
+ const labelIds: Array<ObjectID> | null = this.toQueryableIds(
1775
+ scope.labelIds,
1776
+ );
1777
+
1778
+ if (labelIds) {
1779
+ query.labels = labelIds;
1780
+ }
1781
+
1782
+ return query;
1783
+ }
1784
+
1785
+ /*
1786
+ * null when the kind is empty (it matches everything and adds no clause);
1787
+ * otherwise the kind's usable ids, or one impossible id when none of them
1788
+ * are usable.
1789
+ */
1790
+ private toQueryableIds(
1791
+ ids: Array<string> | undefined,
1792
+ ): Array<ObjectID> | null {
1793
+ if (!ids || ids.length === 0) {
1794
+ return null;
1795
+ }
1796
+
1797
+ const usable: Array<ObjectID> = ids
1798
+ .filter((id: string): boolean => {
1799
+ return ObjectID.isValidUUID(id);
1800
+ })
1801
+ .map((id: string): ObjectID => {
1802
+ return new ObjectID(id);
1803
+ });
1804
+
1805
+ if (usable.length === 0) {
1806
+ return [new ObjectID(UNMATCHABLE_ID)];
1807
+ }
1808
+
1809
+ return usable;
1810
+ }
1811
+
1812
+ /*
1813
+ * The three questions that decide whether a device may carry a policy
1814
+ * monitor at all. All three are about the DEVICE, never about the policy:
1815
+ * a policy cannot make a monitor-backed device pollable.
1816
+ */
1817
+ private isDeviceProvisionable(device: NetworkDevice): boolean {
1818
+ if (device.isArchived) {
1819
+ return false;
1820
+ }
1821
+
1822
+ if (
1823
+ NetworkDeviceMonitoringMethodUtil.isMonitorBacked(device.monitoringMethod)
1824
+ ) {
1825
+ return false;
1826
+ }
1827
+
1828
+ return Boolean(device.probeId);
1829
+ }
1830
+
1831
+ private describeUnprovisionable(device: NetworkDevice): string {
1832
+ if (device.isArchived) {
1833
+ return `device ${device.id?.toString()} is archived`;
1834
+ }
1835
+
1836
+ if (
1837
+ NetworkDeviceMonitoringMethodUtil.isMonitorBacked(device.monitoringMethod)
1838
+ ) {
1839
+ return `device ${device.id?.toString()} is monitor-backed`;
1840
+ }
1841
+
1842
+ return `device ${device.id?.toString()} has no probe`;
1843
+ }
1844
+
1845
+ private toScopeDevice(device: NetworkDevice): {
1846
+ siteId: string | null;
1847
+ networkDeviceRoleId: string | null;
1848
+ labelIds: Array<string>;
1849
+ } {
1850
+ return {
1851
+ siteId: device.siteId?.toString() || null,
1852
+ networkDeviceRoleId: device.networkDeviceRoleId?.toString() || null,
1853
+ labelIds: (device.labels || []).flatMap(
1854
+ (label: { id?: ObjectID | null }): Array<string> => {
1855
+ return label.id ? [label.id.toString()] : [];
1856
+ },
1857
+ ),
1858
+ };
1859
+ }
1860
+
1861
+ /*
1862
+ * Every non-deleted policy of the project, enabled or not, read once per
1863
+ * run. The disabled ones are needed as much as the enabled ones: they are
1864
+ * what tells "a monitor whose owner paused it" (keep) apart from "a
1865
+ * monitor whose owner is gone" (delete).
1866
+ */
1867
+ private async getProjectPolicies(
1868
+ context: PolicyRunContext,
1869
+ ): Promise<Array<NetworkAlertPolicy>> {
1870
+ if (context.policies) {
1871
+ return context.policies;
1872
+ }
1873
+
1874
+ const policies: Array<NetworkAlertPolicy> =
1875
+ await NetworkAlertPolicyService.findBy({
1876
+ query: {
1877
+ projectId: context.projectId,
1878
+ },
1879
+ select: {
1880
+ _id: true,
1881
+ projectId: true,
1882
+ name: true,
1883
+ isEnabled: true,
1884
+ monitorTemplateId: true,
1885
+ scope: true,
1886
+ },
1887
+ limit: LIMIT_PER_PROJECT,
1888
+ skip: 0,
1889
+ props: {
1890
+ isRoot: true,
1891
+ },
1892
+ });
1893
+
1894
+ context.policies = policies;
1895
+
1896
+ return policies;
1897
+ }
1898
+
1899
+ /*
1900
+ * The template, read once per run and re-checked against the project and
1901
+ * the type every time it is loaded. A policy's template was validated when
1902
+ * the policy was saved, but it can be edited, and the engine clones it as
1903
+ * ROOT — so nothing here trusts the policy's word for what it points at.
1904
+ */
1905
+ private async getMonitorTemplate(data: {
1906
+ context: PolicyRunContext;
1907
+ monitorTemplateId: ObjectID;
1908
+ }): Promise<MonitorTemplate | null> {
1909
+ const key: string = data.monitorTemplateId.toString();
1910
+
1911
+ if (data.context.templatesById.has(key)) {
1912
+ return data.context.templatesById.get(key) || null;
1913
+ }
1914
+
1915
+ const template: MonitorTemplate | null =
1916
+ await MonitorTemplateService.findOneBy({
1917
+ query: {
1918
+ _id: data.monitorTemplateId,
1919
+ projectId: data.context.projectId,
1920
+ monitorType: MonitorType.NetworkDevice,
1921
+ },
1922
+ select: {
1923
+ _id: true,
1924
+ projectId: true,
1925
+ monitorType: true,
1926
+ monitorName: true,
1927
+ monitorDescription: true,
1928
+ monitorSteps: true,
1929
+ monitoringInterval: true,
1930
+ minimumProbeAgreement: true,
1931
+ customFields: true,
1932
+ labels: {
1933
+ _id: true,
1934
+ },
1935
+ },
1936
+ props: {
1937
+ isRoot: true,
1938
+ },
1939
+ });
1940
+
1941
+ data.context.templatesById.set(key, template);
1942
+
1943
+ return template;
1944
+ }
1945
+
1946
+ /*
1947
+ * Prerequisite 5, and the reason it is a precheck rather than an error
1948
+ * handler: a project on a plan that cannot hold another monitor would
1949
+ * otherwise produce one failed create per device — five hundred identical
1950
+ * log lines and a lastSyncError that says nothing about the plan. Asked
1951
+ * once per run, remembered, and terminal.
1952
+ *
1953
+ * `force` re-asks after a create failed, so the free-plan ceiling reached
1954
+ * DURING a run (the precheck passed at 9 of 10 monitors) stops the run at
1955
+ * the first refusal instead of at the five hundredth.
1956
+ */
1957
+ private async stopIfPlanRefusesAnotherMonitor(
1958
+ context: PolicyRunContext,
1959
+ force: boolean = false,
1960
+ ): Promise<boolean> {
1961
+ if (context.isStopped) {
1962
+ return true;
1963
+ }
1964
+
1965
+ if (context.planChecked && !force) {
1966
+ return false;
1967
+ }
1968
+
1969
+ context.planChecked = true;
1970
+
1971
+ if (!IsBillingEnabled) {
1972
+ return false;
1973
+ }
1974
+
1975
+ let exception: string | null = null;
1976
+
1977
+ try {
1978
+ const currentPlan: CurrentPlan = await ProjectService.getCurrentPlan(
1979
+ context.projectId,
1980
+ );
1981
+
1982
+ if (currentPlan.isSubscriptionUnpaid) {
1983
+ exception =
1984
+ "This project's subscription is unpaid, so no monitors can be provisioned. Update the payment method and settle the outstanding invoices, and the next sync will provision them.";
1985
+ } else if (currentPlan.plan === PlanType.Free) {
1986
+ const monitorCount: PositiveNumber = await MonitorService.countBy({
1987
+ query: {
1988
+ projectId: context.projectId,
1989
+ monitorType: QueryHelper.any(
1990
+ MonitorTypeHelper.getActiveMonitorTypes(),
1991
+ ),
1992
+ },
1993
+ props: {
1994
+ isRoot: true,
1995
+ },
1996
+ });
1997
+
1998
+ if (monitorCount.toNumber() >= AllowedActiveMonitorCountInFreePlan) {
1999
+ exception = `This project has reached the free plan's limit of ${AllowedActiveMonitorCountInFreePlan} active monitors, so alert policies cannot provision more. Upgrade the plan and the next sync will provision them.`;
2000
+ }
2001
+ }
2002
+ } catch (error) {
2003
+ /*
2004
+ * The billing lookup itself failed. That is NOT a plan refusal — a
2005
+ * Stripe blip must not stop a fleet from being provisioned — so it is
2006
+ * recorded as an ordinary failure and the run carries on.
2007
+ */
2008
+ this.recordFailure(
2009
+ context,
2010
+ `Could not read the project's plan before provisioning monitors: ${error}`,
2011
+ );
2012
+
2013
+ return false;
2014
+ }
2015
+
2016
+ if (!exception) {
2017
+ return false;
2018
+ }
2019
+
2020
+ context.planException = exception;
2021
+ context.isStopped = true;
2022
+
2023
+ logger.warn(
2024
+ `NetworkAlertPolicy engine: stopping this run for project ${context.projectId.toString()} — ${exception}`,
2025
+ { projectId: context.projectId.toString() } as LogAttributes,
2026
+ );
2027
+
2028
+ return true;
2029
+ }
2030
+
2031
+ /*
2032
+ * Is there budget left? Marks the run truncated when there is not, so
2033
+ * callers stop provisioning rather than stop dead: what has been written
2034
+ * stays written, the policy is stamped, and the next sweep continues.
2035
+ */
2036
+ private hasMonitorBudget(context: PolicyRunContext): boolean {
2037
+ if (context.monitorsWritten >= context.monitorBudget) {
2038
+ context.isTruncated = true;
2039
+
2040
+ return false;
2041
+ }
2042
+
2043
+ return true;
2044
+ }
2045
+
2046
+ // ...and spend one unit of it, immediately before a write.
2047
+ private takeMonitorBudget(context: PolicyRunContext): boolean {
2048
+ if (!this.hasMonitorBudget(context)) {
2049
+ return false;
2050
+ }
2051
+
2052
+ context.monitorsWritten++;
2053
+
2054
+ return true;
2055
+ }
2056
+
2057
+ private async deleteMonitors(data: {
2058
+ projectId: ObjectID;
2059
+ monitors: Array<Monitor>;
2060
+ context: PolicyRunContext;
2061
+ reason: string;
2062
+ }): Promise<void> {
2063
+ for (const monitor of data.monitors) {
2064
+ if (!monitor.id) {
2065
+ continue;
2066
+ }
2067
+
2068
+ if (!this.takeMonitorBudget(data.context)) {
2069
+ return;
2070
+ }
2071
+
2072
+ try {
2073
+ /*
2074
+ * Keyed on the policy id the row was read with as well as on the
2075
+ * row's own id, so a monitor that changed hands between the read and
2076
+ * the delete is left to whoever owns it now.
2077
+ */
2078
+ await MonitorService.deleteBy({
2079
+ query: {
2080
+ _id: monitor.id,
2081
+ projectId: data.projectId,
2082
+ networkAlertPolicyId: monitor.networkAlertPolicyId!,
2083
+ },
2084
+ limit: 1,
2085
+ skip: 0,
2086
+ props: {
2087
+ isRoot: true,
2088
+ },
2089
+ });
2090
+
2091
+ data.context.monitorsDeleted++;
2092
+
2093
+ logger.debug(
2094
+ `NetworkAlertPolicy engine: deleted policy-owned monitor ${monitor.id.toString()} because ${data.reason}.`,
2095
+ );
2096
+ } catch (error) {
2097
+ this.recordFailure(
2098
+ data.context,
2099
+ `Could not delete policy-owned monitor ${monitor.id.toString()} (${data.reason}): ${error}`,
2100
+ );
2101
+ }
2102
+ }
2103
+ }
2104
+
2105
+ private async pauseMonitors(data: {
2106
+ projectId: ObjectID;
2107
+ monitors: Array<Monitor>;
2108
+ context: PolicyRunContext;
2109
+ }): Promise<void> {
2110
+ for (const monitor of data.monitors) {
2111
+ if (!monitor.id) {
2112
+ continue;
2113
+ }
2114
+
2115
+ if (!this.takeMonitorBudget(data.context)) {
2116
+ return;
2117
+ }
2118
+
2119
+ try {
2120
+ await MonitorService.updateBy({
2121
+ query: {
2122
+ _id: monitor.id,
2123
+ projectId: data.projectId,
2124
+ networkAlertPolicyId: monitor.networkAlertPolicyId!,
2125
+ },
2126
+ data: {
2127
+ disableActiveMonitoring: true,
2128
+ },
2129
+ limit: 1,
2130
+ skip: 0,
2131
+ props: {
2132
+ isRoot: true,
2133
+ },
2134
+ });
2135
+
2136
+ data.context.monitorsPaused++;
2137
+ } catch (error) {
2138
+ this.recordFailure(
2139
+ data.context,
2140
+ `Could not pause policy-owned monitor ${monitor.id.toString()}: ${error}`,
2141
+ );
2142
+ }
2143
+ }
2144
+ }
2145
+
2146
+ private recordFailure(context: PolicyRunContext, message: string): void {
2147
+ logger.error(`NetworkAlertPolicy engine: ${message}`, {
2148
+ projectId: context.projectId.toString(),
2149
+ } as LogAttributes);
2150
+
2151
+ if (context.failures.length >= MAX_RECORDED_FAILURES_PER_RUN) {
2152
+ return;
2153
+ }
2154
+
2155
+ context.failures.push(message);
2156
+ }
2157
+ }
2158
+
2159
+ export default new NetworkAlertPolicyEngineServiceClass();