@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
@@ -6,6 +6,9 @@ import MonitorService from "./MonitorService";
6
6
  import MonitorStatusService from "./MonitorStatusService";
7
7
  import NetworkDeviceService from "./NetworkDeviceService";
8
8
  import NetworkSiteStatusTimelineService from "./NetworkSiteStatusTimelineService";
9
+ import NetworkSiteTypeService from "./NetworkSiteTypeService";
10
+ import NetworkSnmpCredentialProfileService from "./NetworkSnmpCredentialProfileService";
11
+ import ProbeService from "./ProbeService";
9
12
  import Model from "../../Models/DatabaseModels/NetworkSite";
10
13
  import Alert from "../../Models/DatabaseModels/Alert";
11
14
  import AlertSeverity from "../../Models/DatabaseModels/AlertSeverity";
@@ -14,17 +17,23 @@ import Monitor from "../../Models/DatabaseModels/Monitor";
14
17
  import MonitorStatus from "../../Models/DatabaseModels/MonitorStatus";
15
18
  import NetworkDevice from "../../Models/DatabaseModels/NetworkDevice";
16
19
  import NetworkSiteStatusTimeline from "../../Models/DatabaseModels/NetworkSiteStatusTimeline";
20
+ import NetworkSiteType from "../../Models/DatabaseModels/NetworkSiteType";
21
+ import NetworkSnmpCredentialProfile from "../../Models/DatabaseModels/NetworkSnmpCredentialProfile";
17
22
  import { DisableAutomaticAlertCreation } from "../EnvironmentConfig";
18
23
  import SortOrder from "../../Types/BaseDatabase/SortOrder";
19
24
  import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
20
25
  import CreateBy from "../Types/Database/CreateBy";
21
26
  import DeleteBy from "../Types/Database/DeleteBy";
27
+ import DeleteOneBy from "../Types/Database/DeleteOneBy";
22
28
  import UpdateBy from "../Types/Database/UpdateBy";
29
+ import UpdateOneBy from "../Types/Database/UpdateOneBy";
23
30
  import Query from "../Types/Database/Query";
24
31
  import QueryHelper from "../Types/Database/QueryHelper";
25
32
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
26
33
  import NetworkDeviceHydrationUtil from "../Utils/Monitor/NetworkDeviceHydrationUtil";
27
34
  import logger, { LogAttributes } from "../Utils/Logger";
35
+ import PartialEntity from "../../Types/Database/PartialEntity";
36
+ import { NetworkDeviceMonitoringMethodUtil } from "../../Types/NetworkDevice/NetworkDeviceMonitoringMethod";
28
37
  import LIMIT_MAX, { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
29
38
  import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
30
39
  import { FindWhereProperty } from "../../Types/BaseDatabase/Query";
@@ -32,6 +41,7 @@ import BadDataException from "../../Types/Exception/BadDataException";
32
41
  import MonitorType from "../../Types/Monitor/MonitorType";
33
42
  import ObjectID from "../../Types/ObjectID";
34
43
  import OneUptimeDate from "../../Types/Date";
44
+ import PositiveNumber from "../../Types/PositiveNumber";
35
45
  import Text from "../../Types/Text";
36
46
  import { Raw } from "typeorm";
37
47
  import RelationIdUtil from "../Utils/Database/RelationIdUtil";
@@ -42,6 +52,7 @@ import SiteStatusRollupUtil, {
42
52
  } from "../../Utils/NetworkSite/SiteStatusRollupUtil";
43
53
  import { parseSiteHealthRollupPolicy } from "../../Types/NetworkSite/SiteHealthRollupPolicy";
44
54
  import NetworkSiteMaintenanceSuppression from "../Utils/NetworkSite/NetworkSiteMaintenanceSuppression";
55
+ import NetworkSiteHierarchyLock from "../Utils/NetworkSite/NetworkSiteHierarchyLock";
45
56
  import { AggregateRow } from "../Types/Database/AggregateBy";
46
57
  import AggregateResultUtil from "../Types/Database/AggregateResultUtil";
47
58
  import {
@@ -67,6 +78,118 @@ export interface SiteStatusCount {
67
78
  */
68
79
  const PARENT_SITE_KEYS: Array<string> = ["parentSiteId", "parentSite"];
69
80
 
81
+ /*
82
+ * Like parentSite, the site's type can be written either as its FK or as the
83
+ * serialised relation produced by dashboard forms. Hierarchy validation must
84
+ * inspect both spellings because TypeORM has not resolved the relation when
85
+ * the before hooks run.
86
+ */
87
+ const NETWORK_SITE_TYPE_KEYS: Array<string> = [
88
+ "networkSiteTypeId",
89
+ "networkSiteType",
90
+ ];
91
+
92
+ const PROJECT_KEYS: Array<string> = ["projectId", "project"];
93
+
94
+ /*
95
+ * Both spellings of the site's two monitoring defaults: the probe that polls
96
+ * devices here, and the SNMP credentials they are walked with.
97
+ *
98
+ * Both are references that a device INHERITS - the probe copied onto the
99
+ * device at write (see NetworkDeviceService), the credentials read live at
100
+ * poll time (see NetworkDeviceHydrationUtil.resolveSnmpCredentials). So a
101
+ * cross-project value here is not a cosmetic error on one row: it reaches
102
+ * every device in the subtree. Watching only the FK spelling would leave the
103
+ * dashboard's site form - which posts the relation - unguarded, which is the
104
+ * bug RelationIdUtil exists to document.
105
+ */
106
+ const PROBE_KEYS: Array<string> = ["probeId", "probe"];
107
+ const SNMP_CREDENTIAL_PROFILE_KEYS: Array<string> = [
108
+ "snmpCredentialProfileId",
109
+ "snmpCredentialProfile",
110
+ ];
111
+
112
+ const MATERIALIZED_HIERARCHY_KEYS: Array<string> = [
113
+ "materializedPath",
114
+ "depth",
115
+ ];
116
+
117
+ /*
118
+ * Type edits have to inspect every direct child. Keep each read bounded and
119
+ * page until exhaustion so a very wide site cannot hide invalid edges beyond
120
+ * DatabaseService's single-query limit.
121
+ */
122
+ const DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE: number = 1000;
123
+
124
+ /*
125
+ * Rebase large subtrees in bounded pages. Each successful rewrite removes the
126
+ * row from the old path prefix, so every page must start at offset zero.
127
+ */
128
+ const SUBTREE_REBASE_PAGE_SIZE: number = 1000;
129
+
130
+ /*
131
+ * Model instances initialise optional fields to undefined. Those properties
132
+ * are omissions, not requests to clear a relation; null is the explicit
133
+ * clear value and must still run validation.
134
+ */
135
+ function isRelationWritten(
136
+ data: Record<string, unknown>,
137
+ keys: Array<string>,
138
+ ): boolean {
139
+ return keys.some((key: string) => {
140
+ return key in data && data[key] !== undefined;
141
+ });
142
+ }
143
+
144
+ function normalizeId(id: ObjectID | string): string {
145
+ return id.toString().toLowerCase();
146
+ }
147
+
148
+ function sameId(left: ObjectID | string, right: ObjectID | string): boolean {
149
+ return normalizeId(left) === normalizeId(right);
150
+ }
151
+
152
+ /*
153
+ * RelationIdUtil intentionally returns null for anything it cannot resolve.
154
+ * In a hierarchy hook, however, an unresolvable NON-null value cannot mean
155
+ * "clear": TypeORM may still interpret a raw expression or relation-shaped
156
+ * object during the eventual write. Require each supplied spelling to be an
157
+ * explicit clear or a concrete ID before checking cross-spelling agreement.
158
+ */
159
+ function readStrictRelationId(data: {
160
+ payload: Record<string, unknown>;
161
+ keys: Array<string>;
162
+ relationTitle: string;
163
+ }): ObjectID | null {
164
+ for (const key of data.keys) {
165
+ const value: unknown = data.payload[key];
166
+
167
+ if (typeof value === "function") {
168
+ throw new BadDataException(
169
+ `${key} cannot be set to a raw SQL expression because the network site hierarchy must be validated against an actual ID.`,
170
+ );
171
+ }
172
+
173
+ const isExplicitClear: boolean = value === null || value === "";
174
+
175
+ if (
176
+ value !== undefined &&
177
+ !isExplicitClear &&
178
+ !RelationIdUtil.read(data.payload, [key])
179
+ ) {
180
+ throw new BadDataException(
181
+ `${key} must contain a valid ${data.relationTitle} ID.`,
182
+ );
183
+ }
184
+ }
185
+
186
+ return RelationIdUtil.readConsistent(
187
+ data.payload,
188
+ data.keys,
189
+ data.relationTitle,
190
+ );
191
+ }
192
+
70
193
  /*
71
194
  * Carried from onBeforeUpdate to onUpdateSuccess when an update touches
72
195
  * parentSiteId, so the subtree rebase knows each site's previous state.
@@ -78,9 +201,10 @@ interface ParentChangeCarryForward {
78
201
  }
79
202
 
80
203
  /*
81
- * Carried from onBeforeDelete to onDeleteSuccess: the rows are gone by the
82
- * time the success hook runs, so their pre-delete hierarchy state has to be
83
- * captured up front to repair the orphaned subtree.
204
+ * Carried from onBeforeDelete to onDeleteSuccess. The normal path rejects a
205
+ * delete with surviving children, but retaining the pre-delete hierarchy
206
+ * state lets the success hook repair rows created under older SET NULL
207
+ * schemas or by an in-flight legacy write.
84
208
  */
85
209
  interface DeleteCarryForward {
86
210
  sitesToDelete: Array<Model>;
@@ -91,6 +215,393 @@ export class Service extends DatabaseService<Model> {
91
215
  super(Model);
92
216
  }
93
217
 
218
+ /*
219
+ * Parent/type validation and the eventual write must observe one serialized
220
+ * project hierarchy. The same distributed lock is used by
221
+ * NetworkSiteTypeService, because changing either table can invalidate the
222
+ * other. It surrounds the whole DatabaseService mutation so success-hook
223
+ * subtree maintenance is protected too and finally always releases it.
224
+ */
225
+ @CaptureSpan()
226
+ public override async create(createBy: CreateBy<Model>): Promise<Model> {
227
+ if (createBy.props.ignoreHooks) {
228
+ return await super.create(createBy);
229
+ }
230
+
231
+ const rawData: Record<string, unknown> = createBy.data as unknown as Record<
232
+ string,
233
+ unknown
234
+ >;
235
+ const projectId: ObjectID | null =
236
+ createBy.props.tenantId ||
237
+ RelationIdUtil.readConsistent(
238
+ rawData,
239
+ ["projectId", "project"],
240
+ "Project",
241
+ ) ||
242
+ null;
243
+
244
+ return await NetworkSiteHierarchyLock.runExclusive({
245
+ projectIds: projectId ? [projectId] : [],
246
+ operation: async (): Promise<Model> => {
247
+ return await super.create(createBy);
248
+ },
249
+ });
250
+ }
251
+
252
+ @CaptureSpan()
253
+ public override async updateOneBy(
254
+ updateOneBy: UpdateOneBy<Model>,
255
+ ): Promise<number> {
256
+ if (
257
+ updateOneBy.props.ignoreHooks ||
258
+ !this.updateTouchesHierarchy(updateOneBy.data)
259
+ ) {
260
+ return await super.updateOneBy(updateOneBy);
261
+ }
262
+
263
+ const projectIds: Array<ObjectID | string> =
264
+ await this.findMutationProjectIds({
265
+ query: updateOneBy.query,
266
+ props: updateOneBy.props,
267
+ limit: 1,
268
+ skip: 0,
269
+ isDelete: false,
270
+ });
271
+
272
+ return await NetworkSiteHierarchyLock.runExclusive({
273
+ projectIds,
274
+ operation: async (): Promise<number> => {
275
+ return await super.updateOneBy(updateOneBy);
276
+ },
277
+ });
278
+ }
279
+
280
+ @CaptureSpan()
281
+ public override async updateBy(updateBy: UpdateBy<Model>): Promise<number> {
282
+ if (
283
+ updateBy.props.ignoreHooks ||
284
+ !this.updateTouchesHierarchy(updateBy.data)
285
+ ) {
286
+ return await super.updateBy(updateBy);
287
+ }
288
+
289
+ const projectIds: Array<ObjectID | string> =
290
+ await this.findMutationProjectIds({
291
+ query: updateBy.query,
292
+ props: updateBy.props,
293
+ limit: this.positiveNumberValue(updateBy.limit, LIMIT_MAX),
294
+ skip: this.positiveNumberValue(updateBy.skip, 0),
295
+ isDelete: false,
296
+ });
297
+
298
+ return await NetworkSiteHierarchyLock.runExclusive({
299
+ projectIds,
300
+ operation: async (): Promise<number> => {
301
+ return await super.updateBy(updateBy);
302
+ },
303
+ });
304
+ }
305
+
306
+ @CaptureSpan()
307
+ public override async deleteOneBy(
308
+ deleteOneBy: DeleteOneBy<Model>,
309
+ ): Promise<number> {
310
+ if (deleteOneBy.props.ignoreHooks) {
311
+ return await super.deleteOneBy(deleteOneBy);
312
+ }
313
+
314
+ const projectIds: Array<ObjectID | string> =
315
+ await this.findMutationProjectIds({
316
+ query: deleteOneBy.query,
317
+ props: deleteOneBy.props,
318
+ limit: 1,
319
+ skip: 0,
320
+ isDelete: true,
321
+ });
322
+
323
+ return await NetworkSiteHierarchyLock.runExclusive({
324
+ projectIds,
325
+ operation: async (): Promise<number> => {
326
+ return await super.deleteOneBy(deleteOneBy);
327
+ },
328
+ });
329
+ }
330
+
331
+ @CaptureSpan()
332
+ public override async deleteBy(deleteBy: DeleteBy<Model>): Promise<number> {
333
+ if (deleteBy.props.ignoreHooks) {
334
+ return await super.deleteBy(deleteBy);
335
+ }
336
+
337
+ const projectIds: Array<ObjectID | string> =
338
+ await this.findMutationProjectIds({
339
+ query: deleteBy.query,
340
+ props: deleteBy.props,
341
+ limit: this.positiveNumberValue(deleteBy.limit, LIMIT_MAX),
342
+ skip: this.positiveNumberValue(deleteBy.skip, 0),
343
+ isDelete: true,
344
+ });
345
+
346
+ return await NetworkSiteHierarchyLock.runExclusive({
347
+ projectIds,
348
+ operation: async (): Promise<number> => {
349
+ return await super.deleteBy(deleteBy);
350
+ },
351
+ });
352
+ }
353
+
354
+ @CaptureSpan()
355
+ public override async hardDeleteBy(
356
+ deleteBy: DeleteBy<Model>,
357
+ ): Promise<number> {
358
+ if (deleteBy.props.ignoreHooks) {
359
+ return await super.hardDeleteBy(deleteBy);
360
+ }
361
+
362
+ /*
363
+ * The generic retention cron intentionally queries every tenant at once
364
+ * by deletedAt. Resolve that open-ended query to a closed set of leaf IDs
365
+ * before locking and deleting. Deleting leaves only means a limit can
366
+ * never split a parent from a surviving child; the cron's next iteration
367
+ * naturally works upward through the tree.
368
+ */
369
+ if (
370
+ !NetworkSiteHierarchyLock.isSafeRootMutationScope({
371
+ query: deleteBy.query as unknown as Record<string, unknown>,
372
+ props: deleteBy.props,
373
+ tenantScopeIsClosed: true,
374
+ })
375
+ ) {
376
+ return await this.hardDeleteClosedLeafBatch(deleteBy);
377
+ }
378
+
379
+ const projectIds: Array<ObjectID | string> =
380
+ await this.findMutationProjectIds({
381
+ query: deleteBy.query,
382
+ props: deleteBy.props,
383
+ limit: this.positiveNumberValue(deleteBy.limit, LIMIT_MAX),
384
+ skip: this.positiveNumberValue(deleteBy.skip, 0),
385
+ isDelete: true,
386
+ });
387
+
388
+ return await NetworkSiteHierarchyLock.runExclusive({
389
+ projectIds,
390
+ operation: async (): Promise<number> => {
391
+ return await super.hardDeleteBy(deleteBy);
392
+ },
393
+ });
394
+ }
395
+
396
+ private updateTouchesHierarchy(data: UpdateOneBy<Model>["data"]): boolean {
397
+ const record: Record<string, unknown> = data as unknown as Record<
398
+ string,
399
+ unknown
400
+ >;
401
+
402
+ return (
403
+ isRelationWritten(record, PARENT_SITE_KEYS) ||
404
+ isRelationWritten(record, NETWORK_SITE_TYPE_KEYS) ||
405
+ isRelationWritten(record, PROJECT_KEYS) ||
406
+ isRelationWritten(record, MATERIALIZED_HIERARCHY_KEYS)
407
+ );
408
+ }
409
+
410
+ private positiveNumberValue(
411
+ value: PositiveNumber | number | undefined,
412
+ fallback: number,
413
+ ): number {
414
+ if (value instanceof PositiveNumber) {
415
+ return value.toNumber();
416
+ }
417
+
418
+ return value ?? fallback;
419
+ }
420
+
421
+ private async hardDeleteClosedLeafBatch(
422
+ deleteBy: DeleteBy<Model>,
423
+ ): Promise<number> {
424
+ const requestedLimit: number = this.positiveNumberValue(
425
+ deleteBy.limit,
426
+ LIMIT_MAX,
427
+ );
428
+
429
+ if (requestedLimit <= 0) {
430
+ return 0;
431
+ }
432
+
433
+ const scanPageSize: number = Math.min(
434
+ DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE,
435
+ requestedLimit,
436
+ );
437
+ const leafSites: Array<Model> = [];
438
+ let scanSkip: number = this.positiveNumberValue(deleteBy.skip, 0);
439
+
440
+ while (leafSites.length < requestedLimit) {
441
+ const candidates: Array<Model> = await this.findBy({
442
+ query: deleteBy.query,
443
+ select: {
444
+ _id: true,
445
+ projectId: true,
446
+ },
447
+ sort: { _id: SortOrder.Ascending },
448
+ limit: scanPageSize,
449
+ skip: scanSkip,
450
+ props: { isRoot: true },
451
+ });
452
+
453
+ if (candidates.length === 0) {
454
+ break;
455
+ }
456
+
457
+ const candidateIds: Array<ObjectID> = candidates
458
+ .map((candidate: Model): ObjectID | null => {
459
+ return candidate.id || null;
460
+ })
461
+ .filter((id: ObjectID | null): id is ObjectID => {
462
+ return Boolean(id);
463
+ });
464
+ const parentIdsWithChildren: Set<string> = new Set<string>();
465
+
466
+ for (
467
+ let parentOffset: number = 0;
468
+ parentOffset < candidateIds.length;
469
+ parentOffset += DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE
470
+ ) {
471
+ const parentIdBatch: Array<ObjectID> = candidateIds.slice(
472
+ parentOffset,
473
+ parentOffset + DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE,
474
+ );
475
+ let childSkip: number = 0;
476
+
477
+ while (parentIdBatch.length > 0) {
478
+ const children: Array<Model> = await this.findBy({
479
+ query: {
480
+ parentSiteId: QueryHelper.any(parentIdBatch),
481
+ },
482
+ select: { parentSiteId: true },
483
+ sort: { _id: SortOrder.Ascending },
484
+ limit: DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE,
485
+ skip: childSkip,
486
+ props: { isRoot: true },
487
+ });
488
+
489
+ for (const child of children) {
490
+ if (child.parentSiteId) {
491
+ parentIdsWithChildren.add(normalizeId(child.parentSiteId));
492
+ }
493
+ }
494
+
495
+ if (children.length < DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE) {
496
+ break;
497
+ }
498
+
499
+ childSkip += children.length;
500
+ }
501
+ }
502
+
503
+ for (const candidate of candidates) {
504
+ if (
505
+ candidate.id &&
506
+ candidate.projectId &&
507
+ !parentIdsWithChildren.has(normalizeId(candidate.id))
508
+ ) {
509
+ leafSites.push(candidate);
510
+
511
+ if (leafSites.length === requestedLimit) {
512
+ break;
513
+ }
514
+ }
515
+ }
516
+
517
+ scanSkip += candidates.length;
518
+
519
+ if (candidates.length < scanPageSize) {
520
+ break;
521
+ }
522
+ }
523
+
524
+ if (leafSites.length === 0) {
525
+ return 0;
526
+ }
527
+
528
+ const leafIds: Array<ObjectID> = leafSites.map((site: Model): ObjectID => {
529
+ return site.id!;
530
+ });
531
+
532
+ return await NetworkSiteHierarchyLock.runExclusive({
533
+ projectIds: leafSites.map((site: Model): ObjectID => {
534
+ return site.projectId!;
535
+ }),
536
+ operation: async (): Promise<number> => {
537
+ return await super.hardDeleteBy({
538
+ ...deleteBy,
539
+ query: {
540
+ ...deleteBy.query,
541
+ _id: QueryHelper.any(leafIds),
542
+ },
543
+ limit: leafIds.length,
544
+ skip: 0,
545
+ });
546
+ },
547
+ });
548
+ }
549
+
550
+ private async findMutationProjectIds(data: {
551
+ query: Query<Model>;
552
+ props: DatabaseCommonInteractionProps;
553
+ limit: number;
554
+ skip: number;
555
+ isDelete: boolean;
556
+ }): Promise<Array<ObjectID | string>> {
557
+ NetworkSiteHierarchyLock.assertSafeRootMutationScope({
558
+ query: data.query as unknown as Record<string, unknown>,
559
+ props: data.props,
560
+ tenantScopeIsClosed: data.isDelete,
561
+ });
562
+
563
+ const sites: Array<Model> = await this.findBy({
564
+ query: data.isDelete
565
+ ? this.scopeDeleteQueryToCallerTenant(data.query, data.props)
566
+ : this.scopeQueryToCallerTenant(data.query, data.props),
567
+ select: { projectId: true },
568
+ limit: data.limit,
569
+ skip: data.skip,
570
+ props: { isRoot: true },
571
+ });
572
+
573
+ const projectIds: Array<ObjectID | string> = sites
574
+ .map((site: Model): ObjectID | undefined => {
575
+ return site.projectId;
576
+ })
577
+ .filter((projectId: ObjectID | undefined): projectId is ObjectID => {
578
+ return Boolean(projectId);
579
+ });
580
+
581
+ projectIds.push(
582
+ ...NetworkSiteHierarchyLock.getExplicitProjectIds(
583
+ data.query as unknown as Record<string, unknown>,
584
+ ),
585
+ );
586
+
587
+ if (projectIds.length === 0 && data.props.tenantId) {
588
+ projectIds.push(data.props.tenantId);
589
+ }
590
+
591
+ const seenProjectIds: Set<string> = new Set<string>();
592
+
593
+ return projectIds.filter((projectId: ObjectID | string): boolean => {
594
+ const normalizedProjectId: string = normalizeId(projectId);
595
+
596
+ if (seenProjectIds.has(normalizedProjectId)) {
597
+ return false;
598
+ }
599
+
600
+ seenProjectIds.add(normalizedProjectId);
601
+ return true;
602
+ });
603
+ }
604
+
94
605
  /**
95
606
  * How many sites sit under each rolled-up MonitorStatus, counted in the
96
607
  * database.
@@ -155,7 +666,26 @@ export class Service extends DatabaseService<Model> {
155
666
  query: Query<Model>,
156
667
  props: DatabaseCommonInteractionProps,
157
668
  ): Query<Model> {
158
- if (props.isRoot || !props.tenantId) {
669
+ if (props.isRoot || props.isMasterAdmin || !props.tenantId) {
670
+ return query;
671
+ }
672
+
673
+ return {
674
+ ...query,
675
+ projectId: props.tenantId,
676
+ };
677
+ }
678
+
679
+ /*
680
+ * Root deletes are also tenant-scoped by DeletePermission when tenantId is
681
+ * present. Mirror that exact rule in the preflight read so limit/skip guard
682
+ * the same rows the eventual delete can select.
683
+ */
684
+ private scopeDeleteQueryToCallerTenant(
685
+ query: Query<Model>,
686
+ props: DatabaseCommonInteractionProps,
687
+ ): Query<Model> {
688
+ if (!props.tenantId || props.isMultiTenantRequest) {
159
689
  return query;
160
690
  }
161
691
 
@@ -214,10 +744,10 @@ export class Service extends DatabaseService<Model> {
214
744
  /*
215
745
  * A stored path is trustworthy only when it agrees with parentSiteId: it
216
746
  * must end with the site's own id, and the segment before it must be the
217
- * parent (nothing before it for a root). A delete that nulls parentSiteId,
218
- * or a half-applied move, leaves the two disagreeing - and a stale path
219
- * silently corrupts every prefix query built from it, so treat it as
220
- * missing and let the caller rebuild.
747
+ * parent (nothing before it for a root). A legacy delete that nullified
748
+ * parentSiteId, or a half-applied move, leaves the two disagreeing - and a
749
+ * stale path silently corrupts every prefix query built from it, so treat
750
+ * it as missing and let the caller rebuild.
221
751
  */
222
752
  private isPathConsistent(site: Model): boolean {
223
753
  if (!site.id) {
@@ -245,47 +775,446 @@ export class Service extends DatabaseService<Model> {
245
775
  return parentSegment === parentId;
246
776
  }
247
777
 
778
+ /*
779
+ * Resolve a site type with tenant information and its configured direct
780
+ * parent type. The lookup deliberately runs as root: hook validation occurs
781
+ * before DatabaseService applies the caller's permission-scoped query, so
782
+ * the service must see the referenced row and perform the project check
783
+ * explicitly rather than confuse "foreign" with "missing".
784
+ */
785
+ private async getNetworkSiteTypeForHierarchy(
786
+ networkSiteTypeId: ObjectID,
787
+ cache: Map<string, NetworkSiteType>,
788
+ ): Promise<NetworkSiteType> {
789
+ const key: string = normalizeId(networkSiteTypeId);
790
+ const cached: NetworkSiteType | undefined = cache.get(key);
791
+
792
+ if (cached) {
793
+ return cached;
794
+ }
795
+
796
+ const networkSiteType: NetworkSiteType | null =
797
+ await NetworkSiteTypeService.findOneById({
798
+ id: networkSiteTypeId,
799
+ select: {
800
+ _id: true,
801
+ projectId: true,
802
+ parentNetworkSiteTypeId: true,
803
+ },
804
+ props: {
805
+ isRoot: true,
806
+ },
807
+ });
808
+
809
+ if (!networkSiteType) {
810
+ throw new BadDataException("Network site type not found.");
811
+ }
812
+
813
+ cache.set(key, networkSiteType);
814
+ return networkSiteType;
815
+ }
816
+
817
+ /*
818
+ * Assert one proposed site edge against the type hierarchy. Untyped legacy
819
+ * root rows remain readable/editable, but as soon as a site has a type its
820
+ * placement is exact: a root type has no parent, and a non-root type has a
821
+ * parent site whose type is precisely the configured direct parent type.
822
+ */
823
+ private async validateSiteTypeEdge(data: {
824
+ networkSiteTypeId: ObjectID | null;
825
+ parentSite: Model | null;
826
+ projectId: ObjectID | undefined;
827
+ typeCache: Map<string, NetworkSiteType>;
828
+ }): Promise<void> {
829
+ if (!data.networkSiteTypeId) {
830
+ if (data.parentSite) {
831
+ throw new BadDataException(
832
+ "A network site with a parent must have a network site type.",
833
+ );
834
+ }
835
+
836
+ return;
837
+ }
838
+
839
+ const networkSiteType: NetworkSiteType =
840
+ await this.getNetworkSiteTypeForHierarchy(
841
+ data.networkSiteTypeId,
842
+ data.typeCache,
843
+ );
844
+
845
+ if (
846
+ data.projectId &&
847
+ networkSiteType.projectId &&
848
+ !sameId(networkSiteType.projectId, data.projectId)
849
+ ) {
850
+ throw new BadDataException(
851
+ "Network site type must belong to the same project.",
852
+ );
853
+ }
854
+
855
+ const requiredParentTypeId: ObjectID | null =
856
+ networkSiteType.parentNetworkSiteTypeId || null;
857
+
858
+ if (!requiredParentTypeId) {
859
+ if (data.parentSite) {
860
+ throw new BadDataException(
861
+ "A site with a root network site type cannot have a parent site.",
862
+ );
863
+ }
864
+
865
+ return;
866
+ }
867
+
868
+ if (!data.parentSite) {
869
+ throw new BadDataException(
870
+ "This network site type requires a parent site.",
871
+ );
872
+ }
873
+
874
+ if (
875
+ !data.parentSite.networkSiteTypeId ||
876
+ !sameId(data.parentSite.networkSiteTypeId, requiredParentTypeId)
877
+ ) {
878
+ throw new BadDataException(
879
+ "Parent site must use the configured parent network site type.",
880
+ );
881
+ }
882
+ }
883
+
884
+ /*
885
+ * Changing a site's type also changes what every direct child's type must
886
+ * point at. Validate those reverse edges before the update so one edit
887
+ * cannot strand a previously valid subtree.
888
+ */
889
+ private async validateDirectChildrenForTypeChange(data: {
890
+ site: Model;
891
+ proposedNetworkSiteTypeId: ObjectID | null;
892
+ typeCache: Map<string, NetworkSiteType>;
893
+ }): Promise<void> {
894
+ if (!data.site.id || !data.site.projectId) {
895
+ return;
896
+ }
897
+
898
+ const proposedParent: Model = {
899
+ id: data.site.id,
900
+ projectId: data.site.projectId,
901
+ networkSiteTypeId: data.proposedNetworkSiteTypeId || undefined,
902
+ } as Model;
903
+
904
+ let skip: number = 0;
905
+
906
+ while (true) {
907
+ const children: Array<Model> = await this.findBy({
908
+ query: {
909
+ projectId: data.site.projectId,
910
+ parentSiteId: data.site.id,
911
+ },
912
+ select: {
913
+ _id: true,
914
+ projectId: true,
915
+ networkSiteTypeId: true,
916
+ },
917
+ sort: {
918
+ _id: SortOrder.Ascending,
919
+ },
920
+ limit: DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE,
921
+ skip: skip,
922
+ props: {
923
+ isRoot: true,
924
+ },
925
+ });
926
+
927
+ for (const child of children) {
928
+ await this.validateSiteTypeEdge({
929
+ networkSiteTypeId: child.networkSiteTypeId || null,
930
+ parentSite: proposedParent,
931
+ projectId: child.projectId || data.site.projectId,
932
+ typeCache: data.typeCache,
933
+ });
934
+ }
935
+
936
+ if (children.length < DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE) {
937
+ break;
938
+ }
939
+
940
+ skip += children.length;
941
+ }
942
+ }
943
+
944
+ /*
945
+ * The FK behind `probeId` only requires the Probe row to exist. It does
946
+ * NOT require it to belong to this project, and probe ids reach the server
947
+ * from the browser (the site form's dropdown posts one), so without this
948
+ * check an operator could name another project's probe as this site's
949
+ * default - and NetworkDeviceService would then copy it onto every device
950
+ * created into the site, handing that project's probe a target list inside
951
+ * this one.
952
+ *
953
+ * A GLOBAL probe has no project and is attachable anywhere, which is why
954
+ * this delegates to ProbeService rather than comparing projectIds: the
955
+ * same predicate that decides which probes a monitor may use decides which
956
+ * probe a site may default to.
957
+ */
958
+ private async assertProbeIsAttachableToProject(data: {
959
+ probeId: ObjectID;
960
+ projectId: ObjectID | undefined;
961
+ }): Promise<void> {
962
+ if (!data.projectId) {
963
+ return;
964
+ }
965
+
966
+ const isAttachable: boolean = await ProbeService.isProbeAttachableToProject(
967
+ {
968
+ probeId: data.probeId,
969
+ projectId: data.projectId,
970
+ },
971
+ );
972
+
973
+ if (!isAttachable) {
974
+ throw new BadDataException(
975
+ "Probe not found or it does not belong to this project.",
976
+ );
977
+ }
978
+ }
979
+
980
+ /*
981
+ * Same hole as the probe above, and the consequence is worse: a site's
982
+ * credential profile is read LIVE at poll time for every device in the
983
+ * site that has no credentials of its own
984
+ * (NetworkDeviceHydrationUtil.resolveSnmpCredentials), so a cross-project
985
+ * reference here would put another project's community string on this
986
+ * project's probe's wire. The resolver drops such a reference as a
987
+ * backstop; this is the half that stops it being written at all.
988
+ */
989
+ private async assertSnmpCredentialProfileBelongsToProject(data: {
990
+ snmpCredentialProfileId: ObjectID;
991
+ projectId: ObjectID | undefined;
992
+ }): Promise<void> {
993
+ if (!data.projectId) {
994
+ return;
995
+ }
996
+
997
+ const profile: NetworkSnmpCredentialProfile | null =
998
+ await NetworkSnmpCredentialProfileService.findOneById({
999
+ id: data.snmpCredentialProfileId,
1000
+ select: {
1001
+ _id: true,
1002
+ projectId: true,
1003
+ },
1004
+ props: {
1005
+ isRoot: true,
1006
+ },
1007
+ });
1008
+
1009
+ if (!profile) {
1010
+ throw new BadDataException("SNMP Credential Profile not found.");
1011
+ }
1012
+
1013
+ if (profile.projectId && !sameId(profile.projectId, data.projectId)) {
1014
+ throw new BadDataException(
1015
+ "SNMP Credential Profile must belong to the same project.",
1016
+ );
1017
+ }
1018
+ }
1019
+
1020
+ /*
1021
+ * The site's default probe, inherited: this site's own `probeId`, or the
1022
+ * nearest ancestor that has one.
1023
+ *
1024
+ * Copy-at-write, not read-through — NetworkDeviceService calls this once,
1025
+ * when a device is created into or moved to a site with no probe of its
1026
+ * own, and stamps the answer on the device. That is what makes editing a
1027
+ * site's default a decision about FUTURE devices only: nothing re-reads
1028
+ * this, so no site edit can silently re-point a fleet that is already
1029
+ * polling.
1030
+ *
1031
+ * Nearest ancestor wins, so a Region's probe covers every Market under it
1032
+ * while a Market that names its own overrides it for its own subtree.
1033
+ * `getAncestorIds` returns root-first, hence the reverse walk.
1034
+ */
1035
+ @CaptureSpan()
1036
+ public async resolveDefaultProbeIdForSite(
1037
+ siteId: ObjectID,
1038
+ ): Promise<ObjectID | null> {
1039
+ const site: Model | null = await this.findOneById({
1040
+ id: siteId,
1041
+ select: {
1042
+ _id: true,
1043
+ probeId: true,
1044
+ parentSiteId: true,
1045
+ },
1046
+ props: {
1047
+ isRoot: true,
1048
+ },
1049
+ });
1050
+
1051
+ if (!site) {
1052
+ return null;
1053
+ }
1054
+
1055
+ if (site.probeId) {
1056
+ return site.probeId;
1057
+ }
1058
+
1059
+ /*
1060
+ * A root site has no ancestors, so there is nothing above it to inherit
1061
+ * from. Short-circuited here rather than left to getAncestorIds because
1062
+ * that call is not free: it resolves — and, for a row whose path is
1063
+ * missing or stale, REBUILDS AND PERSISTS — the materialized path. This
1064
+ * runs on the device create path, where most sites are roots and no
1065
+ * device write should be paying for hierarchy maintenance it cannot use.
1066
+ */
1067
+ if (!site.parentSiteId) {
1068
+ return null;
1069
+ }
1070
+
1071
+ const ancestorIds: Array<ObjectID> = await this.getAncestorIds(siteId);
1072
+
1073
+ if (ancestorIds.length === 0) {
1074
+ return null;
1075
+ }
1076
+
1077
+ const ancestors: Array<Model> = await this.findBy({
1078
+ query: {
1079
+ _id: QueryHelper.any(
1080
+ ancestorIds.map((ancestorId: ObjectID) => {
1081
+ return ancestorId.toString();
1082
+ }),
1083
+ ),
1084
+ },
1085
+ select: {
1086
+ _id: true,
1087
+ probeId: true,
1088
+ },
1089
+ limit: LIMIT_MAX,
1090
+ skip: 0,
1091
+ props: {
1092
+ isRoot: true,
1093
+ },
1094
+ });
1095
+
1096
+ const probeIdBySiteId: Map<string, ObjectID> = new Map();
1097
+
1098
+ for (const ancestor of ancestors) {
1099
+ if (ancestor.id && ancestor.probeId) {
1100
+ probeIdBySiteId.set(ancestor.id.toString(), ancestor.probeId);
1101
+ }
1102
+ }
1103
+
1104
+ for (let index: number = ancestorIds.length - 1; index >= 0; index--) {
1105
+ const probeId: ObjectID | undefined = probeIdBySiteId.get(
1106
+ ancestorIds[index]!.toString(),
1107
+ );
1108
+
1109
+ if (probeId) {
1110
+ return probeId;
1111
+ }
1112
+ }
1113
+
1114
+ return null;
1115
+ }
1116
+
248
1117
  @CaptureSpan()
249
1118
  protected override async onBeforeCreate(
250
1119
  createBy: CreateBy<Model>,
251
1120
  ): Promise<OnCreate<Model>> {
252
1121
  let parentPath: string | null = null;
1122
+ let parentSite: Model | null = null;
1123
+ const rawData: Record<string, unknown> = createBy.data as unknown as Record<
1124
+ string,
1125
+ unknown
1126
+ >;
1127
+ const projectId: ObjectID | undefined =
1128
+ createBy.props.tenantId ||
1129
+ RelationIdUtil.readConsistent(
1130
+ rawData,
1131
+ ["projectId", "project"],
1132
+ "Project",
1133
+ ) ||
1134
+ undefined;
253
1135
 
254
1136
  /*
255
1137
  * Both spellings: the dashboard's site form posts the `parentSite`
256
1138
  * relation, not the `parentSiteId` column. See RelationIdUtil.
257
1139
  */
258
- const parentSiteId: ObjectID | null = RelationIdUtil.read(
259
- createBy.data as unknown as Record<string, unknown>,
260
- PARENT_SITE_KEYS,
261
- );
1140
+ const parentSiteId: ObjectID | null = readStrictRelationId({
1141
+ payload: rawData,
1142
+ keys: PARENT_SITE_KEYS,
1143
+ relationTitle: "Parent Site",
1144
+ });
1145
+ const networkSiteTypeId: ObjectID | null = readStrictRelationId({
1146
+ payload: rawData,
1147
+ keys: NETWORK_SITE_TYPE_KEYS,
1148
+ relationTitle: "Network Site Type",
1149
+ });
262
1150
 
263
1151
  if (parentSiteId) {
264
- const parent: Model | null = await this.findOneById({
1152
+ parentSite = await this.findOneById({
265
1153
  id: parentSiteId,
266
1154
  select: {
267
1155
  _id: true,
268
1156
  projectId: true,
1157
+ networkSiteTypeId: true,
269
1158
  },
270
1159
  props: {
271
1160
  isRoot: true,
272
1161
  },
273
1162
  });
274
1163
 
275
- if (!parent) {
1164
+ if (!parentSite) {
276
1165
  throw new BadDataException("Parent site not found.");
277
1166
  }
278
1167
 
279
1168
  if (
280
- createBy.data.projectId &&
281
- parent.projectId &&
282
- parent.projectId.toString() !== createBy.data.projectId.toString()
1169
+ projectId &&
1170
+ parentSite.projectId &&
1171
+ !sameId(parentSite.projectId, projectId)
283
1172
  ) {
284
1173
  throw new BadDataException(
285
1174
  "Parent site must belong to the same project.",
286
1175
  );
287
1176
  }
1177
+ }
1178
+
1179
+ await this.validateSiteTypeEdge({
1180
+ networkSiteTypeId: networkSiteTypeId,
1181
+ parentSite: parentSite,
1182
+ projectId: projectId,
1183
+ typeCache: new Map<string, NetworkSiteType>(),
1184
+ });
1185
+
1186
+ /*
1187
+ * The monitoring defaults are tenant-checked on the way in, in both
1188
+ * spellings. See the constants for why a bad value here is not confined
1189
+ * to this row.
1190
+ */
1191
+ const probeId: ObjectID | null = readStrictRelationId({
1192
+ payload: rawData,
1193
+ keys: PROBE_KEYS,
1194
+ relationTitle: "Probe",
1195
+ });
1196
+
1197
+ if (probeId) {
1198
+ await this.assertProbeIsAttachableToProject({
1199
+ probeId: probeId,
1200
+ projectId: projectId,
1201
+ });
1202
+ }
1203
+
1204
+ const snmpCredentialProfileId: ObjectID | null = readStrictRelationId({
1205
+ payload: rawData,
1206
+ keys: SNMP_CREDENTIAL_PROFILE_KEYS,
1207
+ relationTitle: "SNMP Credential Profile",
1208
+ });
1209
+
1210
+ if (snmpCredentialProfileId) {
1211
+ await this.assertSnmpCredentialProfileBelongsToProject({
1212
+ snmpCredentialProfileId: snmpCredentialProfileId,
1213
+ projectId: projectId,
1214
+ });
1215
+ }
288
1216
 
1217
+ if (parentSiteId) {
289
1218
  parentPath = await this.getMaterializedPathForSite(parentSiteId);
290
1219
  }
291
1220
 
@@ -332,16 +1261,86 @@ export class Service extends DatabaseService<Model> {
332
1261
  protected override async onBeforeUpdate(
333
1262
  updateBy: UpdateBy<Model>,
334
1263
  ): Promise<OnUpdate<Model>> {
335
- const dataKeys: Array<string> = Object.keys(updateBy.data || {});
1264
+ const rawData: Record<string, unknown> = updateBy.data as unknown as Record<
1265
+ string,
1266
+ unknown
1267
+ >;
1268
+ const touchesParent: boolean = isRelationWritten(rawData, PARENT_SITE_KEYS);
1269
+ const touchesNetworkSiteType: boolean = isRelationWritten(
1270
+ rawData,
1271
+ NETWORK_SITE_TYPE_KEYS,
1272
+ );
1273
+ const touchesProject: boolean = isRelationWritten(rawData, PROJECT_KEYS);
1274
+ const touchesMaterializedHierarchy: boolean = isRelationWritten(
1275
+ rawData,
1276
+ MATERIALIZED_HIERARCHY_KEYS,
1277
+ );
1278
+ /*
1279
+ * These two have to be named in the early return, and that is the whole
1280
+ * reason they are here. Setting a site's default probe or credential
1281
+ * profile touches neither the parent nor the type, so a tenancy guard
1282
+ * placed below the return would be dead code on exactly the write it
1283
+ * exists for — the shape the site settings form actually posts.
1284
+ */
1285
+ const touchesProbe: boolean = isRelationWritten(rawData, PROBE_KEYS);
1286
+ const touchesSnmpCredentialProfile: boolean = isRelationWritten(
1287
+ rawData,
1288
+ SNMP_CREDENTIAL_PROFILE_KEYS,
1289
+ );
336
1290
 
337
- if (!RelationIdUtil.isWritten(dataKeys, PARENT_SITE_KEYS)) {
1291
+ if (
1292
+ !touchesParent &&
1293
+ !touchesNetworkSiteType &&
1294
+ !touchesProject &&
1295
+ !touchesMaterializedHierarchy &&
1296
+ !touchesProbe &&
1297
+ !touchesSnmpCredentialProfile
1298
+ ) {
338
1299
  return { updateBy, carryForward: null };
339
1300
  }
340
1301
 
341
- const newParentId: ObjectID | null = RelationIdUtil.read(
342
- updateBy.data as unknown as Record<string, unknown>,
343
- PARENT_SITE_KEYS,
344
- );
1302
+ if (touchesMaterializedHierarchy) {
1303
+ throw new BadDataException(
1304
+ "materializedPath and depth are managed by the Network Site hierarchy and cannot be updated directly.",
1305
+ );
1306
+ }
1307
+
1308
+ const proposedProjectId: ObjectID | null = touchesProject
1309
+ ? readStrictRelationId({
1310
+ payload: rawData,
1311
+ keys: PROJECT_KEYS,
1312
+ relationTitle: "Project",
1313
+ })
1314
+ : null;
1315
+
1316
+ if (touchesProject && !proposedProjectId) {
1317
+ throw new BadDataException(
1318
+ "A Network Site cannot be moved to another project.",
1319
+ );
1320
+ }
1321
+
1322
+ const newParentId: ObjectID | null = touchesParent
1323
+ ? readStrictRelationId({
1324
+ payload: rawData,
1325
+ keys: PARENT_SITE_KEYS,
1326
+ relationTitle: "Parent Site",
1327
+ })
1328
+ : null;
1329
+ const newNetworkSiteTypeId: ObjectID | null = touchesNetworkSiteType
1330
+ ? readStrictRelationId({
1331
+ payload: rawData,
1332
+ keys: NETWORK_SITE_TYPE_KEYS,
1333
+ relationTitle: "Network Site Type",
1334
+ })
1335
+ : null;
1336
+ const updateLimit: number =
1337
+ updateBy.limit instanceof PositiveNumber
1338
+ ? updateBy.limit.toNumber()
1339
+ : updateBy.limit || LIMIT_MAX;
1340
+ const updateSkip: number =
1341
+ updateBy.skip instanceof PositiveNumber
1342
+ ? updateBy.skip.toNumber()
1343
+ : updateBy.skip || 0;
345
1344
 
346
1345
  const previousItems: Array<Model> = await this.findBy({
347
1346
  query: this.scopeQueryToCallerTenant(updateBy.query, updateBy.props),
@@ -349,15 +1348,30 @@ export class Service extends DatabaseService<Model> {
349
1348
  _id: true,
350
1349
  projectId: true,
351
1350
  parentSiteId: true,
1351
+ networkSiteTypeId: true,
352
1352
  materializedPath: true,
353
1353
  },
354
- limit: LIMIT_MAX,
355
- skip: 0,
1354
+ limit: updateLimit,
1355
+ skip: updateSkip,
356
1356
  props: {
357
1357
  isRoot: true,
358
1358
  },
359
1359
  });
360
1360
 
1361
+ if (touchesProject) {
1362
+ for (const item of previousItems) {
1363
+ if (
1364
+ !item.projectId ||
1365
+ !proposedProjectId ||
1366
+ !sameId(item.projectId, proposedProjectId)
1367
+ ) {
1368
+ throw new BadDataException(
1369
+ "A Network Site cannot be moved to another project.",
1370
+ );
1371
+ }
1372
+ }
1373
+ }
1374
+
361
1375
  /*
362
1376
  * Same-project assertion for EVERY parentSiteId write, including the
363
1377
  * detach case (parentSiteId: null) which has no parent to compare
@@ -368,7 +1382,7 @@ export class Service extends DatabaseService<Model> {
368
1382
  for (const item of previousItems) {
369
1383
  if (
370
1384
  item.projectId &&
371
- item.projectId.toString() !== updateBy.props.tenantId.toString()
1385
+ !sameId(item.projectId, updateBy.props.tenantId)
372
1386
  ) {
373
1387
  throw new BadDataException(
374
1388
  "Network site must belong to the same project.",
@@ -377,33 +1391,93 @@ export class Service extends DatabaseService<Model> {
377
1391
  }
378
1392
  }
379
1393
 
1394
+ /*
1395
+ * One check per DISTINCT project in the matched set, because a single
1396
+ * updateBy can span more than one project when a root caller issues it,
1397
+ * and the payload names one probe / one profile for all of them. Reading
1398
+ * the ids here (rather than above the previousItems read) keeps a
1399
+ * conflicting-spelling payload refused on every write shape.
1400
+ */
1401
+ if (touchesProbe || touchesSnmpCredentialProfile) {
1402
+ const newProbeId: ObjectID | null = touchesProbe
1403
+ ? readStrictRelationId({
1404
+ payload: rawData,
1405
+ keys: PROBE_KEYS,
1406
+ relationTitle: "Probe",
1407
+ })
1408
+ : null;
1409
+ const newSnmpCredentialProfileId: ObjectID | null =
1410
+ touchesSnmpCredentialProfile
1411
+ ? readStrictRelationId({
1412
+ payload: rawData,
1413
+ keys: SNMP_CREDENTIAL_PROFILE_KEYS,
1414
+ relationTitle: "SNMP Credential Profile",
1415
+ })
1416
+ : null;
1417
+
1418
+ // A clear (null) points at nothing and has nothing to check.
1419
+ if (newProbeId || newSnmpCredentialProfileId) {
1420
+ const checkedProjectIds: Set<string> = new Set();
1421
+
1422
+ for (const item of previousItems) {
1423
+ if (
1424
+ !item.projectId ||
1425
+ checkedProjectIds.has(normalizeId(item.projectId))
1426
+ ) {
1427
+ continue;
1428
+ }
1429
+ checkedProjectIds.add(normalizeId(item.projectId));
1430
+
1431
+ if (newProbeId) {
1432
+ await this.assertProbeIsAttachableToProject({
1433
+ probeId: newProbeId,
1434
+ projectId: item.projectId,
1435
+ });
1436
+ }
1437
+
1438
+ if (newSnmpCredentialProfileId) {
1439
+ await this.assertSnmpCredentialProfileBelongsToProject({
1440
+ snmpCredentialProfileId: newSnmpCredentialProfileId,
1441
+ projectId: item.projectId,
1442
+ });
1443
+ }
1444
+ }
1445
+ }
1446
+ }
1447
+
1448
+ if (!touchesParent && !touchesNetworkSiteType) {
1449
+ return { updateBy, carryForward: null };
1450
+ }
1451
+
380
1452
  let newParentPath: string | null = null;
1453
+ let newParent: Model | null = null;
381
1454
 
382
- if (newParentId) {
383
- const parent: Model | null = await this.findOneById({
1455
+ if (touchesParent && newParentId) {
1456
+ newParent = await this.findOneById({
384
1457
  id: newParentId,
385
1458
  select: {
386
1459
  _id: true,
387
1460
  projectId: true,
1461
+ networkSiteTypeId: true,
388
1462
  },
389
1463
  props: {
390
1464
  isRoot: true,
391
1465
  },
392
1466
  });
393
1467
 
394
- if (!parent) {
1468
+ if (!newParent) {
395
1469
  throw new BadDataException("Parent site not found.");
396
1470
  }
397
1471
 
398
1472
  for (const item of previousItems) {
399
- if (item.id && item.id.toString() === newParentId.toString()) {
1473
+ if (item.id && sameId(item.id, newParentId)) {
400
1474
  throw new BadDataException("A site cannot be its own parent.");
401
1475
  }
402
1476
 
403
1477
  if (
404
1478
  item.projectId &&
405
- parent.projectId &&
406
- item.projectId.toString() !== parent.projectId.toString()
1479
+ newParent.projectId &&
1480
+ !sameId(item.projectId, newParent.projectId)
407
1481
  ) {
408
1482
  throw new BadDataException(
409
1483
  "Parent site must belong to the same project.",
@@ -428,6 +1502,84 @@ export class Service extends DatabaseService<Model> {
428
1502
  }
429
1503
  }
430
1504
 
1505
+ const typeCache: Map<string, NetworkSiteType> = new Map();
1506
+ const existingParents: Map<string, Model> = new Map();
1507
+
1508
+ for (const item of previousItems) {
1509
+ let proposedParent: Model | null = null;
1510
+
1511
+ if (touchesParent) {
1512
+ proposedParent = newParent;
1513
+ } else if (item.parentSiteId) {
1514
+ const currentParentId: string = normalizeId(item.parentSiteId);
1515
+ proposedParent = existingParents.get(currentParentId) || null;
1516
+
1517
+ if (!proposedParent) {
1518
+ proposedParent = await this.findOneById({
1519
+ id: item.parentSiteId,
1520
+ select: {
1521
+ _id: true,
1522
+ projectId: true,
1523
+ networkSiteTypeId: true,
1524
+ },
1525
+ props: {
1526
+ isRoot: true,
1527
+ },
1528
+ });
1529
+
1530
+ if (!proposedParent) {
1531
+ throw new BadDataException("Parent site not found.");
1532
+ }
1533
+
1534
+ existingParents.set(currentParentId, proposedParent);
1535
+ }
1536
+
1537
+ if (
1538
+ item.projectId &&
1539
+ proposedParent.projectId &&
1540
+ !sameId(item.projectId, proposedParent.projectId)
1541
+ ) {
1542
+ throw new BadDataException(
1543
+ "Parent site must belong to the same project.",
1544
+ );
1545
+ }
1546
+ }
1547
+
1548
+ const proposedNetworkSiteTypeId: ObjectID | null = touchesNetworkSiteType
1549
+ ? newNetworkSiteTypeId
1550
+ : item.networkSiteTypeId || null;
1551
+
1552
+ await this.validateSiteTypeEdge({
1553
+ networkSiteTypeId: proposedNetworkSiteTypeId,
1554
+ parentSite: proposedParent,
1555
+ projectId: item.projectId,
1556
+ typeCache: typeCache,
1557
+ });
1558
+
1559
+ const previousNetworkSiteTypeId: string | null = item.networkSiteTypeId
1560
+ ? normalizeId(item.networkSiteTypeId)
1561
+ : null;
1562
+ const proposedNetworkSiteTypeIdString: string | null =
1563
+ proposedNetworkSiteTypeId
1564
+ ? normalizeId(proposedNetworkSiteTypeId)
1565
+ : null;
1566
+
1567
+ if (
1568
+ touchesNetworkSiteType &&
1569
+ previousNetworkSiteTypeId !== proposedNetworkSiteTypeIdString
1570
+ ) {
1571
+ await this.validateDirectChildrenForTypeChange({
1572
+ site: item,
1573
+ proposedNetworkSiteTypeId: proposedNetworkSiteTypeId,
1574
+ typeCache: typeCache,
1575
+ });
1576
+ }
1577
+ }
1578
+
1579
+ if (!touchesParent) {
1580
+ return { updateBy, carryForward: null };
1581
+ }
1582
+
431
1583
  const carryForward: ParentChangeCarryForward = {
432
1584
  previousItems: previousItems,
433
1585
  newParentId: newParentId,
@@ -494,7 +1646,22 @@ export class Service extends DatabaseService<Model> {
494
1646
  }),
495
1647
  );
496
1648
 
497
- for (const previousItem of parentChange.previousItems) {
1649
+ /*
1650
+ * A bulk update can include both an ancestor and one of its descendants.
1651
+ * Move the deepest roots first; otherwise rebasing the ancestor changes
1652
+ * the descendant branch away from the latter's old prefix before its own
1653
+ * subtree has been processed.
1654
+ */
1655
+ const previousItemsDeepestFirst: Array<Model> = [
1656
+ ...parentChange.previousItems,
1657
+ ].sort((left: Model, right: Model): number => {
1658
+ return (
1659
+ MaterializedPathUtil.segmentsOf(right.materializedPath).length -
1660
+ MaterializedPathUtil.segmentsOf(left.materializedPath).length
1661
+ );
1662
+ });
1663
+
1664
+ for (const previousItem of previousItemsDeepestFirst) {
498
1665
  if (!previousItem.id || !updatedIds.has(previousItem.id.toString())) {
499
1666
  continue;
500
1667
  }
@@ -520,44 +1687,53 @@ export class Service extends DatabaseService<Model> {
520
1687
 
521
1688
  // ...then its entire subtree in one prefix query.
522
1689
  if (oldPath) {
523
- const descendants: Array<Model> = await this.findBy({
524
- query: {
525
- projectId: previousItem.projectId!,
526
- materializedPath: this.pathStartsWith(oldPath),
527
- },
528
- select: {
529
- _id: true,
530
- materializedPath: true,
531
- },
532
- limit: LIMIT_MAX,
533
- skip: 0,
534
- props: {
535
- isRoot: true,
536
- },
537
- });
1690
+ while (true) {
1691
+ const descendants: Array<Model> = await this.findBy({
1692
+ query: {
1693
+ projectId: previousItem.projectId!,
1694
+ materializedPath: this.pathStartsWith(oldPath),
1695
+ },
1696
+ select: {
1697
+ _id: true,
1698
+ materializedPath: true,
1699
+ },
1700
+ sort: {
1701
+ _id: SortOrder.Ascending,
1702
+ },
1703
+ limit: SUBTREE_REBASE_PAGE_SIZE,
1704
+ skip: 0,
1705
+ props: {
1706
+ isRoot: true,
1707
+ },
1708
+ });
538
1709
 
539
- for (const descendant of descendants) {
540
- if (
541
- !descendant.id ||
542
- !descendant.materializedPath ||
543
- descendant.id.toString() === previousItem.id.toString()
544
- ) {
545
- continue;
1710
+ for (const descendant of descendants) {
1711
+ if (
1712
+ !descendant.id ||
1713
+ !descendant.materializedPath ||
1714
+ descendant.id.toString() === previousItem.id.toString()
1715
+ ) {
1716
+ continue;
1717
+ }
1718
+
1719
+ const rebasedPath: string = MaterializedPathUtil.rebasePaths(
1720
+ oldPath,
1721
+ newPath,
1722
+ [descendant.materializedPath],
1723
+ )[0]!;
1724
+
1725
+ await this.updateColumnsByIdWithoutHooks({
1726
+ id: descendant.id,
1727
+ data: {
1728
+ materializedPath: rebasedPath,
1729
+ depth: MaterializedPathUtil.depthOf(rebasedPath),
1730
+ },
1731
+ });
546
1732
  }
547
1733
 
548
- const rebasedPath: string = MaterializedPathUtil.rebasePaths(
549
- oldPath,
550
- newPath,
551
- [descendant.materializedPath],
552
- )[0]!;
553
-
554
- await this.updateColumnsByIdWithoutHooks({
555
- id: descendant.id,
556
- data: {
557
- materializedPath: rebasedPath,
558
- depth: MaterializedPathUtil.depthOf(rebasedPath),
559
- },
560
- });
1734
+ if (descendants.length < SUBTREE_REBASE_PAGE_SIZE) {
1735
+ break;
1736
+ }
561
1737
  }
562
1738
  }
563
1739
 
@@ -598,21 +1774,117 @@ export class Service extends DatabaseService<Model> {
598
1774
  protected override async onBeforeDelete(
599
1775
  deleteBy: DeleteBy<Model>,
600
1776
  ): Promise<OnDelete<Model>> {
1777
+ const deleteLimit: number =
1778
+ deleteBy.limit instanceof PositiveNumber
1779
+ ? deleteBy.limit.toNumber()
1780
+ : deleteBy.limit || LIMIT_MAX;
1781
+ const deleteSkip: number =
1782
+ deleteBy.skip instanceof PositiveNumber
1783
+ ? deleteBy.skip.toNumber()
1784
+ : deleteBy.skip || 0;
1785
+
601
1786
  const sitesToDelete: Array<Model> = await this.findBy({
602
- query: this.scopeQueryToCallerTenant(deleteBy.query, deleteBy.props),
1787
+ query: this.scopeDeleteQueryToCallerTenant(
1788
+ deleteBy.query,
1789
+ deleteBy.props,
1790
+ ),
603
1791
  select: {
604
1792
  _id: true,
605
1793
  projectId: true,
606
1794
  parentSiteId: true,
607
1795
  materializedPath: true,
608
1796
  },
609
- limit: LIMIT_MAX,
610
- skip: 0,
1797
+ limit: deleteLimit,
1798
+ skip: deleteSkip,
611
1799
  props: {
612
1800
  isRoot: true,
613
1801
  },
614
1802
  });
615
1803
 
1804
+ const deletingSiteIds: Set<string> = new Set(
1805
+ sitesToDelete
1806
+ .map((site: Model): string | null => {
1807
+ return site.id ? normalizeId(site.id) : null;
1808
+ })
1809
+ .filter((siteId: string | null): siteId is string => {
1810
+ return Boolean(siteId);
1811
+ }),
1812
+ );
1813
+
1814
+ const deletingSiteIdList: Array<string> = Array.from(deletingSiteIds);
1815
+ const deletingProjectIdList: Array<string> = Array.from(
1816
+ new Set(
1817
+ sitesToDelete
1818
+ .map((site: Model): string | null => {
1819
+ return site.projectId ? normalizeId(site.projectId) : null;
1820
+ })
1821
+ .filter((projectId: string | null): projectId is string => {
1822
+ return Boolean(projectId);
1823
+ }),
1824
+ ),
1825
+ );
1826
+
1827
+ /*
1828
+ * A valid child type explicitly names the deleted site's type as its
1829
+ * required direct parent type. Legacy SET NULL/orphan-repair behaviour
1830
+ * therefore cannot produce a valid edge: promoting the child to root or
1831
+ * attaching it to the grandparent both violate its type. Reject the
1832
+ * delete unless every direct child is part of this same bulk delete.
1833
+ *
1834
+ * Parent ids and result rows are both batched so neither a wide delete nor
1835
+ * a wide site is silently truncated at a service query limit.
1836
+ */
1837
+ for (
1838
+ let parentIdOffset: number = 0;
1839
+ parentIdOffset < deletingSiteIdList.length;
1840
+ parentIdOffset += DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE
1841
+ ) {
1842
+ const parentIdBatch: Array<string> = deletingSiteIdList.slice(
1843
+ parentIdOffset,
1844
+ parentIdOffset + DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE,
1845
+ );
1846
+ let childSkip: number = 0;
1847
+
1848
+ while (true) {
1849
+ const directChildren: Array<Model> = await this.findBy({
1850
+ query: {
1851
+ projectId: QueryHelper.any(deletingProjectIdList),
1852
+ parentSiteId: QueryHelper.any(parentIdBatch),
1853
+ },
1854
+ select: {
1855
+ _id: true,
1856
+ parentSiteId: true,
1857
+ },
1858
+ sort: {
1859
+ _id: SortOrder.Ascending,
1860
+ },
1861
+ limit: DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE,
1862
+ skip: childSkip,
1863
+ props: {
1864
+ isRoot: true,
1865
+ },
1866
+ });
1867
+
1868
+ const hasSurvivingChild: boolean = directChildren.some(
1869
+ (child: Model): boolean => {
1870
+ return !child.id || !deletingSiteIds.has(normalizeId(child.id));
1871
+ },
1872
+ );
1873
+
1874
+ if (hasSurvivingChild) {
1875
+ throw new BadDataException(
1876
+ "A network site with child sites cannot be deleted. Move or delete its child sites first.",
1877
+ );
1878
+ }
1879
+
1880
+ if (directChildren.length < DIRECT_CHILD_TYPE_VALIDATION_PAGE_SIZE) {
1881
+ break;
1882
+ }
1883
+
1884
+ childSkip += directChildren.length;
1885
+ }
1886
+ }
1887
+
616
1888
  const carryForward: DeleteCarryForward = {
617
1889
  sitesToDelete: sitesToDelete,
618
1890
  };
@@ -621,15 +1893,12 @@ export class Service extends DatabaseService<Model> {
621
1893
  }
622
1894
 
623
1895
  /*
624
- * parentSiteId is declared onDelete: "SET NULL", so Postgres detaches the
625
- * deleted site's direct children but leaves their materializedPath - and
626
- * their whole subtree's - routed through a row that no longer exists. That
627
- * strands the subtree: the children endpoint (which reads parentSiteId)
628
- * shows them at the root while the rollup engine (which reads
629
- * materializedPath) still folds them into the dead ancestor's chain, double
630
- * counting every outage. Re-attach the orphans to the deleted site's own
631
- * parent - NULL when it was a root, which is exactly what the FK did - and
632
- * rebase the subtree paths so both readers agree again.
1896
+ * New schemas use a non-nullifying foreign key and onBeforeDelete rejects
1897
+ * surviving children, so this repair is normally a no-op. Keep it as a
1898
+ * defensive bridge for a database that has not applied the FK migration
1899
+ * yet, or for a legacy write already in flight during an upgrade: reattach
1900
+ * any detached children and rebase their subtree paths so parentSiteId and
1901
+ * materializedPath agree.
633
1902
  */
634
1903
  @CaptureSpan()
635
1904
  protected override async onDeleteSuccess(
@@ -699,58 +1968,67 @@ export class Service extends DatabaseService<Model> {
699
1968
  const deletedDepth: number =
700
1969
  MaterializedPathUtil.segmentsOf(oldPath).length;
701
1970
 
702
- const descendants: Array<Model> = await this.findBy({
703
- query: {
704
- projectId: deletedSite.projectId!,
705
- materializedPath: this.pathStartsWith(oldPath),
706
- },
707
- select: {
708
- _id: true,
709
- materializedPath: true,
710
- },
711
- limit: LIMIT_MAX,
712
- skip: 0,
713
- props: {
714
- isRoot: true,
715
- },
716
- });
1971
+ while (true) {
1972
+ const descendants: Array<Model> = await this.findBy({
1973
+ query: {
1974
+ projectId: deletedSite.projectId!,
1975
+ materializedPath: this.pathStartsWith(oldPath),
1976
+ },
1977
+ select: {
1978
+ _id: true,
1979
+ materializedPath: true,
1980
+ },
1981
+ sort: {
1982
+ _id: SortOrder.Ascending,
1983
+ },
1984
+ limit: SUBTREE_REBASE_PAGE_SIZE,
1985
+ skip: 0,
1986
+ props: {
1987
+ isRoot: true,
1988
+ },
1989
+ });
717
1990
 
718
- for (const descendant of descendants) {
719
- if (
720
- !descendant.id ||
721
- !descendant.materializedPath ||
722
- descendant.id.toString() === deletedSite.id.toString()
723
- ) {
724
- continue;
725
- }
1991
+ for (const descendant of descendants) {
1992
+ if (
1993
+ !descendant.id ||
1994
+ !descendant.materializedPath ||
1995
+ descendant.id.toString() === deletedSite.id.toString()
1996
+ ) {
1997
+ continue;
1998
+ }
726
1999
 
727
- const tailSegments: Array<string> = MaterializedPathUtil.segmentsOf(
728
- descendant.materializedPath,
729
- ).slice(deletedDepth);
2000
+ const tailSegments: Array<string> = MaterializedPathUtil.segmentsOf(
2001
+ descendant.materializedPath,
2002
+ ).slice(deletedDepth);
730
2003
 
731
- if (tailSegments.length === 0) {
732
- continue;
733
- }
2004
+ if (tailSegments.length === 0) {
2005
+ continue;
2006
+ }
734
2007
 
735
- let rebasedPath: string | null = parentPath;
736
- for (const segment of tailSegments) {
737
- rebasedPath = MaterializedPathUtil.buildPath(rebasedPath, segment);
738
- }
2008
+ let rebasedPath: string | null = parentPath;
2009
+ for (const segment of tailSegments) {
2010
+ rebasedPath = MaterializedPathUtil.buildPath(rebasedPath, segment);
2011
+ }
739
2012
 
740
- const data: Record<string, unknown> = {
741
- materializedPath: rebasedPath!,
742
- depth: MaterializedPathUtil.depthOf(rebasedPath!),
743
- };
2013
+ const updateData: Record<string, unknown> = {
2014
+ materializedPath: rebasedPath!,
2015
+ depth: MaterializedPathUtil.depthOf(rebasedPath!),
2016
+ };
744
2017
 
745
- // A direct child is the one the FK just detached - give it a parent back.
746
- if (tailSegments.length === 1) {
747
- data["parentSiteId"] = deletedSite.parentSiteId || null;
2018
+ // A direct child is the one the FK just detached - give it a parent back.
2019
+ if (tailSegments.length === 1) {
2020
+ updateData["parentSiteId"] = deletedSite.parentSiteId || null;
2021
+ }
2022
+
2023
+ await this.updateColumnsByIdWithoutHooks({
2024
+ id: descendant.id,
2025
+ data: updateData as any,
2026
+ });
748
2027
  }
749
2028
 
750
- await this.updateColumnsByIdWithoutHooks({
751
- id: descendant.id,
752
- data: data as any,
753
- });
2029
+ if (descendants.length < SUBTREE_REBASE_PAGE_SIZE) {
2030
+ break;
2031
+ }
754
2032
  }
755
2033
 
756
2034
  /*
@@ -1617,8 +2895,11 @@ export class Service extends DatabaseService<Model> {
1617
2895
  */
1618
2896
 
1619
2897
  /*
1620
- * Called by MonitorService.changeMonitorStatus after a status persists.
1621
- * Resolves which NetworkDevices these monitors report on, stamps those
2898
+ * Called after a monitor's current status persists - from
2899
+ * MonitorStatusTimelineService.onCreateSuccess / onDeleteSuccess (the one
2900
+ * path every status change, probe-driven or manual, passes through) and
2901
+ * from MonitorService.refreshMonitorCurrentStatus when a repair moves the
2902
+ * id. Resolves which NetworkDevices these monitors report on, stamps those
1622
2903
  * devices' currentMonitorStatusId, then recomputes the rollup for every
1623
2904
  * affected site chain. Never throws - a rollup failure must never break a
1624
2905
  * monitor status change.
@@ -1632,6 +2913,26 @@ export class Service extends DatabaseService<Model> {
1632
2913
  * monitor-backed path (monitoringMethod "Monitor") for gear that does
1633
2914
  * not speak SNMP, so ANY monitor type qualifies — a Ping monitor on an
1634
2915
  * access point is the whole point of it.
2916
+ *
2917
+ * What gets stamped depends on how the device is monitored:
2918
+ *
2919
+ * - every device gets currentMonitorStatusId, which the pill, the site
2920
+ * rollup and the topology node read.
2921
+ * - a MONITOR-BACKED device also gets isReachable, derived from the
2922
+ * status row (`!isOfflineState`, the same offline-end reading
2923
+ * DeviceReachabilityUtil uses). Nothing polls such a device, so the
2924
+ * column is NULL forever otherwise - and the device list's summary
2925
+ * tiles and its Status filter count and filter on isReachable in SQL,
2926
+ * which is why a bound ping-only device sat under "Pending" there while
2927
+ * its own pill said Up. The server keeps the two in sync so the list
2928
+ * agrees with itself.
2929
+ * - an SNMP device's isReachable is left alone: the walk owns it
2930
+ * (NetworkInventoryUtil.updateFromWalk), and a Network Device monitor
2931
+ * going Degraded must not overwrite what the probe actually found.
2932
+ *
2933
+ * The status row is read at most once per call, and only when at least one
2934
+ * collected device is monitor-backed, so an all-SNMP estate costs no extra
2935
+ * query.
1635
2936
  */
1636
2937
  @CaptureSpan()
1637
2938
  public async onMonitorStatusChanged(data: {
@@ -1697,6 +2998,8 @@ export class Service extends DatabaseService<Model> {
1697
2998
  select: {
1698
2999
  _id: true,
1699
3000
  siteId: true,
3001
+ // Decides whether isReachable is stamped alongside the status.
3002
+ monitoringMethod: true,
1700
3003
  },
1701
3004
  limit: LIMIT_MAX,
1702
3005
  skip: 0,
@@ -1716,6 +3019,8 @@ export class Service extends DatabaseService<Model> {
1716
3019
  select: {
1717
3020
  _id: true,
1718
3021
  siteId: true,
3022
+ // Decides whether isReachable is stamped alongside the status.
3023
+ monitoringMethod: true,
1719
3024
  },
1720
3025
  limit: LIMIT_MAX,
1721
3026
  skip: 0,
@@ -1731,15 +3036,83 @@ export class Service extends DatabaseService<Model> {
1731
3036
  return;
1732
3037
  }
1733
3038
 
3039
+ /*
3040
+ * Resolve the status row lazily - once, and only if a monitor-backed
3041
+ * device is in the set - because it is only needed to derive
3042
+ * isReachable, and the SNMP-only case must stay one query cheaper.
3043
+ *
3044
+ * `undefined` afterwards means "do not touch isReachable": either no
3045
+ * device needs it, or the row could not be found in this project (a
3046
+ * status deleted between the timeline write and this call, or one
3047
+ * from another tenant). The id is still stamped in that case so the
3048
+ * pill keeps moving; a stale reachability is the lesser harm next to
3049
+ * a device that stops reporting altogether.
3050
+ */
3051
+ const hasMonitorBackedDevice: boolean = devices.some(
3052
+ (device: NetworkDevice) => {
3053
+ return NetworkDeviceMonitoringMethodUtil.isMonitorBacked(
3054
+ device.monitoringMethod,
3055
+ );
3056
+ },
3057
+ );
3058
+
3059
+ let monitorBackedIsReachable: boolean | undefined = undefined;
3060
+
3061
+ if (hasMonitorBackedDevice) {
3062
+ const status: MonitorStatus | null =
3063
+ await MonitorStatusService.findOneBy({
3064
+ query: {
3065
+ _id: data.monitorStatusId,
3066
+ projectId: data.projectId,
3067
+ },
3068
+ select: {
3069
+ _id: true,
3070
+ isOfflineState: true,
3071
+ },
3072
+ props: {
3073
+ isRoot: true,
3074
+ },
3075
+ });
3076
+
3077
+ if (status) {
3078
+ monitorBackedIsReachable = !status.isOfflineState;
3079
+ } else {
3080
+ logger.warn(
3081
+ `NetworkSiteService.onMonitorStatusChanged: monitor status ${data.monitorStatusId.toString()} was not found in project ${data.projectId.toString()}; stamping the status id on the bound network devices but leaving isReachable unchanged.`,
3082
+ {
3083
+ projectId: data.projectId.toString(),
3084
+ monitorStatusId: data.monitorStatusId.toString(),
3085
+ } as LogAttributes,
3086
+ );
3087
+ }
3088
+ }
3089
+
1734
3090
  for (const device of devices) {
1735
3091
  if (!device.id) {
1736
3092
  continue;
1737
3093
  }
3094
+
3095
+ const stamp: PartialEntity<NetworkDevice> = {
3096
+ currentMonitorStatusId: data.monitorStatusId,
3097
+ };
3098
+
3099
+ /*
3100
+ * Only a monitor-backed device gets isReachable from here. The key
3101
+ * is left OUT of the payload for an SNMP device rather than set to
3102
+ * undefined, so the walk's verdict is provably untouched.
3103
+ */
3104
+ if (
3105
+ monitorBackedIsReachable !== undefined &&
3106
+ NetworkDeviceMonitoringMethodUtil.isMonitorBacked(
3107
+ device.monitoringMethod,
3108
+ )
3109
+ ) {
3110
+ stamp.isReachable = monitorBackedIsReachable;
3111
+ }
3112
+
1738
3113
  await NetworkDeviceService.updateColumnsByIdWithoutHooks({
1739
3114
  id: device.id,
1740
- data: {
1741
- currentMonitorStatusId: data.monitorStatusId,
1742
- },
3115
+ data: stamp,
1743
3116
  });
1744
3117
  }
1745
3118