@oneuptime/common 12.0.32 → 12.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (597) hide show
  1. package/Models/AnalyticsModels/Span.ts +14 -0
  2. package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
  3. package/Models/DatabaseModels/Index.ts +10 -0
  4. package/Models/DatabaseModels/Monitor.ts +76 -0
  5. package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
  6. package/Models/DatabaseModels/NetworkDevice.ts +176 -1
  7. package/Models/DatabaseModels/NetworkSite.ts +201 -2
  8. package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
  9. package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
  10. package/Models/DatabaseModels/TelemetryException.ts +119 -0
  11. package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
  12. package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
  13. package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
  14. package/Server/API/EnterpriseLicenseAPI.ts +391 -64
  15. package/Server/API/LlmProviderAPI.ts +137 -22
  16. package/Server/EnvironmentConfig.ts +14 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  24. package/Server/Infrastructure/QueueWorker.ts +38 -8
  25. package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
  26. package/Server/Middleware/ProjectAuthorization.ts +11 -0
  27. package/Server/Middleware/SCIMAuthorization.ts +12 -0
  28. package/Server/Middleware/TelemetryIngest.ts +11 -0
  29. package/Server/Services/AIBillingService.ts +101 -27
  30. package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
  31. package/Server/Services/EnterpriseLicenseService.ts +55 -0
  32. package/Server/Services/Index.ts +10 -0
  33. package/Server/Services/MonitorService.ts +143 -21
  34. package/Server/Services/MonitorStatusTimelineService.ts +150 -8
  35. package/Server/Services/MonitorTemplateService.ts +217 -1
  36. package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
  37. package/Server/Services/NetworkAlertPolicyService.ts +944 -0
  38. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +9 -10
  39. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
  40. package/Server/Services/NetworkDeviceService.ts +1032 -73
  41. package/Server/Services/NetworkSiteService.ts +1502 -129
  42. package/Server/Services/NetworkSiteTypeService.ts +1216 -0
  43. package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
  44. package/Server/Services/NotificationService.ts +118 -28
  45. package/Server/Services/ProjectService.ts +105 -48
  46. package/Server/Services/StatusPagePrivateUserService.ts +103 -3
  47. package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
  48. package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
  49. package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
  50. package/Server/Services/UserNotificationSettingService.ts +62 -25
  51. package/Server/Services/UserService.ts +95 -0
  52. package/Server/Types/Database/QueryHelper.ts +2 -2
  53. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
  54. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
  55. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
  56. package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
  57. package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
  58. package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
  59. package/Server/Utils/DataSource/HttpFetch.ts +9 -2
  60. package/Server/Utils/EmailRollup/EmailRollupConstants.ts +98 -0
  61. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +872 -0
  62. package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
  63. package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
  64. package/Server/Utils/LLM/LLMService.ts +78 -0
  65. package/Server/Utils/LogRedaction.ts +8 -0
  66. package/Server/Utils/Logger.ts +79 -1
  67. package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
  68. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
  69. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
  70. package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
  71. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +49 -0
  72. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
  73. package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
  74. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +43 -0
  75. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
  76. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
  77. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
  78. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
  79. package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
  80. package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
  81. package/Server/Utils/OutboundUserAgent.ts +152 -0
  82. package/Server/Utils/StartServer.ts +51 -19
  83. package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
  84. package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
  85. package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
  86. package/Server/Utils/Telemetry.ts +198 -51
  87. package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
  88. package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +134 -33
  89. package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
  90. package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
  91. package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
  92. package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
  93. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +18 -9
  94. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
  95. package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
  96. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
  97. package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
  98. package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
  99. package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
  100. package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
  101. package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
  102. package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +41 -5
  103. package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
  104. package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
  105. package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
  106. package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
  107. package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
  108. package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
  109. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
  110. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
  111. package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
  112. package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
  113. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
  114. package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
  115. package/Tests/Server/Infrastructure/Postgres/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
  116. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
  117. package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
  118. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
  119. package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
  120. package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
  121. package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
  122. package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
  123. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
  124. package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
  125. package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
  126. package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
  127. package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
  128. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +47 -4
  129. package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
  130. package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
  131. package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
  132. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
  133. package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
  134. package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
  135. package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
  136. package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
  137. package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
  138. package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
  139. package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
  140. package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
  141. package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
  142. package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
  143. package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
  144. package/Tests/Server/Services/UserEmailChangePasswordResetExpiry.test.ts +472 -0
  145. package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
  146. package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
  147. package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
  148. package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +856 -0
  149. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +102 -1
  150. package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
  151. package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
  152. package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
  153. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
  154. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
  155. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -0
  156. package/Tests/Server/Utils/Captcha.test.ts +422 -0
  157. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +96 -2
  158. package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
  159. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
  160. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
  161. package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
  162. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +752 -0
  163. package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
  164. package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
  165. package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
  166. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
  167. package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
  168. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
  169. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
  170. package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
  171. package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
  172. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
  173. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
  174. package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
  175. package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
  176. package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
  177. package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
  178. package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
  179. package/Tests/Server/Utils/Telemetry.test.ts +456 -66
  180. package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
  181. package/Tests/Types/Monitor/MonitorStepDatabaseMonitor.test.ts +243 -0
  182. package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
  183. package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
  184. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
  185. package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
  186. package/Tests/Types/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
  187. package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
  188. package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
  189. package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -0
  190. package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
  191. package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
  192. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +15 -0
  193. package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
  194. package/Tests/UI/Components/SideMenuItem.test.tsx +226 -4
  195. package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
  196. package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -0
  197. package/Tests/UI/Utils/PageScrollLock.test.tsx +377 -0
  198. package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
  199. package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
  200. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
  201. package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
  202. package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
  203. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
  204. package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
  205. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
  206. package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
  207. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
  208. package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
  209. package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
  210. package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
  211. package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
  212. package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
  213. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
  214. package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
  215. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
  216. package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
  217. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
  218. package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -0
  219. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
  220. package/Types/AI/ExceptionAIClassification.ts +10 -24
  221. package/Types/Email/EmailTemplateType.ts +2 -0
  222. package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
  223. package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
  224. package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
  225. package/Types/Exception/ApiException.ts +10 -0
  226. package/Types/Exception/BadDataException.ts +11 -0
  227. package/Types/Exception/BadRequestException.ts +11 -0
  228. package/Types/Exception/Exception.ts +65 -0
  229. package/Types/Exception/ForbiddenException.ts +10 -0
  230. package/Types/Exception/NotAuthenticatedException.ts +10 -0
  231. package/Types/Exception/NotAuthorizedException.ts +10 -0
  232. package/Types/Exception/NotFoundException.ts +11 -0
  233. package/Types/Exception/PayloadTooLargeException.ts +11 -0
  234. package/Types/Exception/PaymentRequiredException.ts +10 -0
  235. package/Types/Exception/ServiceUnavailableException.ts +10 -0
  236. package/Types/Exception/SsoAuthorizationException.ts +10 -0
  237. package/Types/Exception/TenantNotFoundException.ts +11 -0
  238. package/Types/Exception/TimeoutException.ts +10 -0
  239. package/Types/Exception/TooManyRequestsException.ts +10 -0
  240. package/Types/Exception/UnableToReachServer.ts +10 -0
  241. package/Types/Exception/WebsiteRequestException.ts +10 -0
  242. package/Types/Monitor/CriteriaFilter.ts +60 -2
  243. package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
  244. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
  245. package/Types/Monitor/MonitorCriteriaInstance.ts +76 -0
  246. package/Types/Monitor/MonitorMetricType.ts +71 -0
  247. package/Types/Monitor/MonitorStep.ts +76 -0
  248. package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
  249. package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
  250. package/Types/Monitor/MonitorType.ts +47 -1
  251. package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
  252. package/Types/Monitor/SqlConnectionConfig.ts +31 -0
  253. package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
  254. package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
  255. package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
  256. package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
  257. package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
  258. package/Types/Permission.ts +90 -0
  259. package/Types/Probe/ProbeMonitorResponse.ts +16 -0
  260. package/Types/Telemetry/ErrorClass.ts +274 -0
  261. package/Types/Telemetry/UnitOfWork.ts +59 -0
  262. package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
  263. package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
  264. package/UI/Components/Modal/Modal.tsx +2 -8
  265. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
  266. package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
  267. package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
  268. package/UI/Components/SideMenu/SideMenu.tsx +123 -5
  269. package/UI/Components/SideMenu/SideMenuItem.tsx +76 -84
  270. package/UI/Components/SideMenu/SideMenuSection.tsx +55 -23
  271. package/UI/Components/SideOver/SideOver.tsx +21 -20
  272. package/UI/Utils/PageScrollLock.ts +79 -3
  273. package/UI/Utils/PermissionGate.ts +61 -0
  274. package/UI/Utils/SensitiveUrlToken.ts +112 -0
  275. package/UI/Utils/TestLLMProvider.ts +11 -0
  276. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
  277. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
  278. package/Utils/Monitor/MonitorMetricType.ts +153 -1
  279. package/Utils/Monitor/NetworkTopologyUtil.ts +23 -3
  280. package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
  281. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
  282. package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
  283. package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
  284. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
  285. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
  286. package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
  287. package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
  288. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
  289. package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
  290. package/build/dist/Models/AnalyticsModels/Span.js +14 -0
  291. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  292. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +59 -0
  293. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  294. package/build/dist/Models/DatabaseModels/Index.js +10 -0
  295. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  296. package/build/dist/Models/DatabaseModels/Monitor.js +75 -0
  297. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  298. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js +713 -0
  299. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
  300. package/build/dist/Models/DatabaseModels/NetworkDevice.js +180 -1
  301. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  302. package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
  303. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
  304. package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
  305. package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
  306. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
  307. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
  308. package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
  309. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  310. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js +363 -0
  311. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
  312. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
  313. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
  314. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
  315. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
  316. package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
  317. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  318. package/build/dist/Server/API/LlmProviderAPI.js +108 -13
  319. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  320. package/build/dist/Server/EnvironmentConfig.js +12 -0
  321. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  322. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
  323. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
  324. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
  325. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
  326. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
  327. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
  328. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
  329. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
  330. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
  331. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
  332. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
  333. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js.map +1 -0
  334. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  335. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  336. package/build/dist/Server/Infrastructure/QueueWorker.js +33 -5
  337. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  338. package/build/dist/Server/Middleware/BearerTokenAuthorization.js +12 -0
  339. package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
  340. package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
  341. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  342. package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
  343. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
  344. package/build/dist/Server/Middleware/TelemetryIngest.js +11 -0
  345. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  346. package/build/dist/Server/Services/AIBillingService.js +70 -16
  347. package/build/dist/Server/Services/AIBillingService.js.map +1 -1
  348. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js +167 -0
  349. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
  350. package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
  351. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  352. package/build/dist/Server/Services/Index.js +10 -0
  353. package/build/dist/Server/Services/Index.js.map +1 -1
  354. package/build/dist/Server/Services/MonitorService.js +119 -21
  355. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  356. package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
  357. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  358. package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
  359. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  360. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
  361. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
  362. package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
  363. package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
  364. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +10 -9
  365. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  366. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
  367. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  368. package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
  369. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  370. package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
  371. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  372. package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
  373. package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
  374. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
  375. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
  376. package/build/dist/Server/Services/NotificationService.js +80 -17
  377. package/build/dist/Server/Services/NotificationService.js.map +1 -1
  378. package/build/dist/Server/Services/ProjectService.js +66 -30
  379. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  380. package/build/dist/Server/Services/StatusPagePrivateUserService.js +92 -2
  381. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  382. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js +76 -0
  383. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
  384. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
  385. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
  386. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
  387. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
  388. package/build/dist/Server/Services/UserNotificationSettingService.js +46 -20
  389. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  390. package/build/dist/Server/Services/UserService.js +90 -0
  391. package/build/dist/Server/Services/UserService.js.map +1 -1
  392. package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
  393. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  394. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
  395. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  396. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
  397. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  398. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
  399. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  400. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
  401. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
  402. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
  403. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
  404. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js +59 -0
  405. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
  406. package/build/dist/Server/Utils/DataSource/HttpFetch.js +2 -1
  407. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
  408. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +91 -0
  409. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
  410. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +691 -0
  411. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
  412. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
  413. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
  414. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
  415. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
  416. package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
  417. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  418. package/build/dist/Server/Utils/LogRedaction.js +8 -0
  419. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  420. package/build/dist/Server/Utils/Logger.js +63 -1
  421. package/build/dist/Server/Utils/Logger.js.map +1 -1
  422. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js +141 -0
  423. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
  424. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  425. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  426. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +51 -1
  427. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  428. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
  429. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
  430. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +37 -0
  431. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  432. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
  433. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  434. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  435. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  436. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +32 -0
  437. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  438. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
  439. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  440. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
  441. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  442. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
  443. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  444. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
  445. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  446. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js +30 -17
  447. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
  448. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
  449. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
  450. package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
  451. package/build/dist/Server/Utils/OutboundUserAgent.js.map +1 -0
  452. package/build/dist/Server/Utils/StartServer.js +38 -14
  453. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  454. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +28 -8
  455. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  456. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
  457. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js.map +1 -0
  458. package/build/dist/Server/Utils/Telemetry/SpanUtil.js +29 -0
  459. package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
  460. package/build/dist/Server/Utils/Telemetry.js +162 -46
  461. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  462. package/build/dist/Types/AI/ExceptionAIClassification.js +10 -24
  463. package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -1
  464. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  465. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  466. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
  467. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
  468. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
  469. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
  470. package/build/dist/Types/Exception/ApiException.js +9 -0
  471. package/build/dist/Types/Exception/ApiException.js.map +1 -1
  472. package/build/dist/Types/Exception/BadDataException.js +10 -0
  473. package/build/dist/Types/Exception/BadDataException.js.map +1 -1
  474. package/build/dist/Types/Exception/BadRequestException.js +10 -0
  475. package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
  476. package/build/dist/Types/Exception/Exception.js +56 -0
  477. package/build/dist/Types/Exception/Exception.js.map +1 -1
  478. package/build/dist/Types/Exception/ForbiddenException.js +9 -0
  479. package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
  480. package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
  481. package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
  482. package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
  483. package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
  484. package/build/dist/Types/Exception/NotFoundException.js +10 -0
  485. package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
  486. package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
  487. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
  488. package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
  489. package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
  490. package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
  491. package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
  492. package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
  493. package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
  494. package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
  495. package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
  496. package/build/dist/Types/Exception/TimeoutException.js +9 -0
  497. package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
  498. package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
  499. package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
  500. package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
  501. package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
  502. package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
  503. package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
  504. package/build/dist/Types/Monitor/CriteriaFilter.js +45 -2
  505. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  506. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
  507. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
  508. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
  509. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
  510. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +70 -0
  511. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  512. package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
  513. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  514. package/build/dist/Types/Monitor/MonitorStep.js +54 -0
  515. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  516. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
  517. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
  518. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
  519. package/build/dist/Types/Monitor/MonitorType.js +45 -1
  520. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  521. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
  522. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
  523. package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
  524. package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
  525. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
  526. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
  527. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
  528. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
  529. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
  530. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
  531. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
  532. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
  533. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
  534. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js.map +1 -0
  535. package/build/dist/Types/Permission.js +80 -0
  536. package/build/dist/Types/Permission.js.map +1 -1
  537. package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
  538. package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
  539. package/build/dist/Types/Telemetry/UnitOfWork.js +59 -0
  540. package/build/dist/Types/Telemetry/UnitOfWork.js.map +1 -0
  541. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +2 -7
  542. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  543. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +3 -0
  544. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  545. package/build/dist/UI/Components/Modal/Modal.js +2 -7
  546. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  547. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +39 -0
  548. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  549. package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
  550. package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
  551. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
  552. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
  553. package/build/dist/UI/Components/SideMenu/SideMenu.js +67 -5
  554. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  555. package/build/dist/UI/Components/SideMenu/SideMenuItem.js +49 -53
  556. package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
  557. package/build/dist/UI/Components/SideMenu/SideMenuSection.js +25 -7
  558. package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
  559. package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
  560. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  561. package/build/dist/UI/Utils/PageScrollLock.js +31 -3
  562. package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
  563. package/build/dist/UI/Utils/PermissionGate.js +42 -1
  564. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  565. package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
  566. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -0
  567. package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
  568. package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
  569. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
  570. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
  571. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
  572. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  573. package/build/dist/Utils/Monitor/MonitorMetricType.js +109 -1
  574. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  575. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +8 -3
  576. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  577. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
  578. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
  579. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
  580. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  581. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
  582. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
  583. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
  584. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
  585. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
  586. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  587. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
  588. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  589. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
  590. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
  591. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
  592. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
  593. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
  594. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  595. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
  596. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js.map +1 -0
  597. package/package.json +2 -2
@@ -1,10 +1,1226 @@
1
+ import CreateBy from "../Types/Database/CreateBy";
2
+ import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
3
+ import DeleteBy from "../Types/Database/DeleteBy";
4
+ import DeleteOneBy from "../Types/Database/DeleteOneBy";
5
+ import Select from "../Types/Database/Select";
6
+ import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
7
+ import Query from "../Types/Database/Query";
8
+ import QueryHelper from "../Types/Database/QueryHelper";
9
+ import UpdateBy from "../Types/Database/UpdateBy";
10
+ import UpdateOneBy from "../Types/Database/UpdateOneBy";
1
11
  import DatabaseService from "./DatabaseService";
12
+ import NetworkSiteService from "./NetworkSiteService";
13
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
14
+ import RelationIdUtil from "../Utils/Database/RelationIdUtil";
15
+ import NetworkSiteHierarchyLock from "../Utils/NetworkSite/NetworkSiteHierarchyLock";
2
16
  import Model from "../../Models/DatabaseModels/NetworkSiteType";
17
+ import NetworkSite from "../../Models/DatabaseModels/NetworkSite";
18
+ import NetworkSiteTypeHierarchyUtil from "../../Utils/NetworkSite/TypeHierarchyUtil";
19
+ import SortOrder from "../../Types/BaseDatabase/SortOrder";
20
+ import BadDataException from "../../Types/Exception/BadDataException";
21
+ import LIMIT_MAX from "../../Types/Database/LimitMax";
22
+ import ObjectID from "../../Types/ObjectID";
23
+ import PositiveNumber from "../../Types/PositiveNumber";
24
+
25
+ const PARENT_NETWORK_SITE_TYPE_KEYS: Array<string> = [
26
+ "parentNetworkSiteTypeId",
27
+ "parentNetworkSiteType",
28
+ ];
29
+
30
+ const PROJECT_KEYS: Array<string> = ["projectId", "project"];
31
+
32
+ const EXISTING_SITES_DO_NOT_MATCH_MESSAGE: string =
33
+ "This site type's parent cannot be changed because existing sites do not match the proposed hierarchy. Create a new site type under the desired parent, then move and reassign the sites to it.";
34
+
35
+ const REFERENCE_VALIDATION_BATCH_SIZE: number = 1000;
36
+
37
+ const normalizeId: (id: ObjectID | string) => string = (
38
+ id: ObjectID | string,
39
+ ): string => {
40
+ return id.toString().toLowerCase();
41
+ };
42
+
43
+ const sameId: (left: ObjectID | string, right: ObjectID | string) => boolean = (
44
+ left: ObjectID | string,
45
+ right: ObjectID | string,
46
+ ): boolean => {
47
+ return normalizeId(left) === normalizeId(right);
48
+ };
49
+
50
+ /*
51
+ * Model instances contain properties initialised to undefined. Those are
52
+ * omissions, not writes: TypeORM drops them before producing INSERT/SET.
53
+ * Null, on the other hand, is an explicit request to make this a root type.
54
+ */
55
+ const isAnyKeyWritten: (
56
+ data: Record<string, unknown>,
57
+ keys: Array<string>,
58
+ ) => boolean = (
59
+ data: Record<string, unknown>,
60
+ keys: Array<string>,
61
+ ): boolean => {
62
+ return keys.some((key: string) => {
63
+ return key in data && data[key] !== undefined;
64
+ });
65
+ };
66
+
67
+ const assertNoSqlExpression: (
68
+ data: Record<string, unknown>,
69
+ keys: Array<string>,
70
+ ) => void = (data: Record<string, unknown>, keys: Array<string>): void => {
71
+ for (const key of keys) {
72
+ if (typeof data[key] === "function") {
73
+ throw new BadDataException(
74
+ `${key} cannot be set to a raw SQL expression because the site type hierarchy must be validated against an actual parent ID.`,
75
+ );
76
+ }
77
+ }
78
+ };
79
+
80
+ const assertIsUnitLevelIsNotSqlExpression: (
81
+ data: Record<string, unknown>,
82
+ ) => void = (data: Record<string, unknown>): void => {
83
+ if (typeof data["isUnitLevel"] === "function") {
84
+ throw new BadDataException(
85
+ "isUnitLevel cannot be set to a raw SQL expression because unit-level leaf rules must be validated against an actual boolean value.",
86
+ );
87
+ }
88
+ };
3
89
 
4
90
  export class Service extends DatabaseService<Model> {
5
91
  public constructor() {
6
92
  super(Model);
7
93
  }
94
+
95
+ /*
96
+ * NetworkSite and NetworkSiteType validate one shared graph. Keep the Redis
97
+ * mutex around the complete DatabaseService mutation (before hooks, write,
98
+ * and success hooks), not inside an individual hook, so every error path
99
+ * releases it and a concurrent site/type request cannot validate stale
100
+ * project state.
101
+ */
102
+ @CaptureSpan()
103
+ public override async create(createBy: CreateBy<Model>): Promise<Model> {
104
+ if (createBy.props.ignoreHooks) {
105
+ return await super.create(createBy);
106
+ }
107
+
108
+ const projectId: ObjectID | null =
109
+ createBy.props.tenantId ||
110
+ this.readProjectId(createBy.data as unknown as Record<string, unknown>) ||
111
+ null;
112
+
113
+ return await NetworkSiteHierarchyLock.runExclusive({
114
+ projectIds: projectId ? [projectId] : [],
115
+ operation: async (): Promise<Model> => {
116
+ return await super.create(createBy);
117
+ },
118
+ });
119
+ }
120
+
121
+ @CaptureSpan()
122
+ public override async updateOneBy(
123
+ updateOneBy: UpdateOneBy<Model>,
124
+ ): Promise<number> {
125
+ if (
126
+ updateOneBy.props.ignoreHooks ||
127
+ !this.updateTouchesHierarchy(updateOneBy.data)
128
+ ) {
129
+ return await super.updateOneBy(updateOneBy);
130
+ }
131
+
132
+ const projectIds: Array<ObjectID | string> =
133
+ await this.findMutationProjectIds({
134
+ query: updateOneBy.query,
135
+ props: updateOneBy.props,
136
+ limit: 1,
137
+ skip: 0,
138
+ isDelete: false,
139
+ });
140
+
141
+ return await NetworkSiteHierarchyLock.runExclusive({
142
+ projectIds,
143
+ operation: async (): Promise<number> => {
144
+ return await super.updateOneBy(updateOneBy);
145
+ },
146
+ });
147
+ }
148
+
149
+ @CaptureSpan()
150
+ public override async updateBy(updateBy: UpdateBy<Model>): Promise<number> {
151
+ if (
152
+ updateBy.props.ignoreHooks ||
153
+ !this.updateTouchesHierarchy(updateBy.data)
154
+ ) {
155
+ return await super.updateBy(updateBy);
156
+ }
157
+
158
+ const projectIds: Array<ObjectID | string> =
159
+ await this.findMutationProjectIds({
160
+ query: updateBy.query,
161
+ props: updateBy.props,
162
+ limit: this.positiveNumberValue(updateBy.limit, LIMIT_MAX),
163
+ skip: this.positiveNumberValue(updateBy.skip, 0),
164
+ isDelete: false,
165
+ });
166
+
167
+ return await NetworkSiteHierarchyLock.runExclusive({
168
+ projectIds,
169
+ operation: async (): Promise<number> => {
170
+ return await super.updateBy(updateBy);
171
+ },
172
+ });
173
+ }
174
+
175
+ @CaptureSpan()
176
+ public override async deleteOneBy(
177
+ deleteOneBy: DeleteOneBy<Model>,
178
+ ): Promise<number> {
179
+ if (deleteOneBy.props.ignoreHooks) {
180
+ return await super.deleteOneBy(deleteOneBy);
181
+ }
182
+
183
+ const projectIds: Array<ObjectID | string> =
184
+ await this.findMutationProjectIds({
185
+ query: deleteOneBy.query,
186
+ props: deleteOneBy.props,
187
+ limit: 1,
188
+ skip: 0,
189
+ isDelete: true,
190
+ });
191
+
192
+ return await NetworkSiteHierarchyLock.runExclusive({
193
+ projectIds,
194
+ operation: async (): Promise<number> => {
195
+ return await super.deleteOneBy(deleteOneBy);
196
+ },
197
+ });
198
+ }
199
+
200
+ @CaptureSpan()
201
+ public override async deleteBy(deleteBy: DeleteBy<Model>): Promise<number> {
202
+ if (deleteBy.props.ignoreHooks) {
203
+ return await super.deleteBy(deleteBy);
204
+ }
205
+
206
+ const projectIds: Array<ObjectID | string> =
207
+ await this.findMutationProjectIds({
208
+ query: deleteBy.query,
209
+ props: deleteBy.props,
210
+ limit: this.positiveNumberValue(deleteBy.limit, LIMIT_MAX),
211
+ skip: this.positiveNumberValue(deleteBy.skip, 0),
212
+ isDelete: true,
213
+ });
214
+
215
+ return await NetworkSiteHierarchyLock.runExclusive({
216
+ projectIds,
217
+ operation: async (): Promise<number> => {
218
+ return await super.deleteBy(deleteBy);
219
+ },
220
+ });
221
+ }
222
+
223
+ @CaptureSpan()
224
+ public override async hardDeleteBy(
225
+ deleteBy: DeleteBy<Model>,
226
+ ): Promise<number> {
227
+ if (deleteBy.props.ignoreHooks) {
228
+ return await super.hardDeleteBy(deleteBy);
229
+ }
230
+
231
+ /*
232
+ * The retention cron uses one root deletedAt query across all projects.
233
+ * Convert it to a closed batch of unused leaf types before locking. A
234
+ * parent and child can therefore never be split by the batch limit; once
235
+ * leaves are removed, the cron's next iteration can work upward.
236
+ */
237
+ if (
238
+ !NetworkSiteHierarchyLock.isSafeRootMutationScope({
239
+ query: deleteBy.query as unknown as Record<string, unknown>,
240
+ props: deleteBy.props,
241
+ tenantScopeIsClosed: true,
242
+ })
243
+ ) {
244
+ return await this.hardDeleteClosedLeafBatch(deleteBy);
245
+ }
246
+
247
+ const projectIds: Array<ObjectID | string> =
248
+ await this.findMutationProjectIds({
249
+ query: deleteBy.query,
250
+ props: deleteBy.props,
251
+ limit: this.positiveNumberValue(deleteBy.limit, LIMIT_MAX),
252
+ skip: this.positiveNumberValue(deleteBy.skip, 0),
253
+ isDelete: true,
254
+ });
255
+
256
+ return await NetworkSiteHierarchyLock.runExclusive({
257
+ projectIds,
258
+ operation: async (): Promise<number> => {
259
+ return await super.hardDeleteBy(deleteBy);
260
+ },
261
+ });
262
+ }
263
+
264
+ private updateTouchesHierarchy(data: UpdateOneBy<Model>["data"]): boolean {
265
+ const record: Record<string, unknown> = data as unknown as Record<
266
+ string,
267
+ unknown
268
+ >;
269
+
270
+ return (
271
+ isAnyKeyWritten(record, PARENT_NETWORK_SITE_TYPE_KEYS) ||
272
+ ("isUnitLevel" in record && record["isUnitLevel"] !== undefined) ||
273
+ isAnyKeyWritten(record, PROJECT_KEYS)
274
+ );
275
+ }
276
+
277
+ private positiveNumberValue(
278
+ value: PositiveNumber | number | undefined,
279
+ fallback: number,
280
+ ): number {
281
+ if (value instanceof PositiveNumber) {
282
+ return value.toNumber();
283
+ }
284
+
285
+ return value ?? fallback;
286
+ }
287
+
288
+ private async hardDeleteClosedLeafBatch(
289
+ deleteBy: DeleteBy<Model>,
290
+ ): Promise<number> {
291
+ const requestedLimit: number = this.positiveNumberValue(
292
+ deleteBy.limit,
293
+ LIMIT_MAX,
294
+ );
295
+
296
+ if (requestedLimit <= 0) {
297
+ return 0;
298
+ }
299
+
300
+ const scanPageSize: number = Math.min(
301
+ REFERENCE_VALIDATION_BATCH_SIZE,
302
+ requestedLimit,
303
+ );
304
+ const leafTypes: Array<Model> = [];
305
+ let scanSkip: number = this.positiveNumberValue(deleteBy.skip, 0);
306
+
307
+ while (leafTypes.length < requestedLimit) {
308
+ const candidates: Array<Model> = await this.findBy({
309
+ query: deleteBy.query,
310
+ select: { _id: true, projectId: true },
311
+ sort: { _id: SortOrder.Ascending },
312
+ limit: scanPageSize,
313
+ skip: scanSkip,
314
+ props: { isRoot: true },
315
+ });
316
+
317
+ if (candidates.length === 0) {
318
+ break;
319
+ }
320
+
321
+ const candidateIds: Array<ObjectID> = candidates
322
+ .map((candidate: Model): ObjectID | null => {
323
+ return candidate.id || null;
324
+ })
325
+ .filter((id: ObjectID | null): id is ObjectID => {
326
+ return Boolean(id);
327
+ });
328
+ const referencedTypeIds: Set<string> = new Set<string>();
329
+
330
+ for (
331
+ let candidateOffset: number = 0;
332
+ candidateOffset < candidateIds.length;
333
+ candidateOffset += REFERENCE_VALIDATION_BATCH_SIZE
334
+ ) {
335
+ const candidateIdBatch: Array<ObjectID> = candidateIds.slice(
336
+ candidateOffset,
337
+ candidateOffset + REFERENCE_VALIDATION_BATCH_SIZE,
338
+ );
339
+ let childSkip: number = 0;
340
+
341
+ while (candidateIdBatch.length > 0) {
342
+ const childTypes: Array<Model> = await this.findBy({
343
+ query: {
344
+ parentNetworkSiteTypeId: QueryHelper.any(candidateIdBatch),
345
+ },
346
+ select: { parentNetworkSiteTypeId: true },
347
+ sort: { _id: SortOrder.Ascending },
348
+ limit: REFERENCE_VALIDATION_BATCH_SIZE,
349
+ skip: childSkip,
350
+ props: { isRoot: true },
351
+ });
352
+
353
+ for (const childType of childTypes) {
354
+ if (childType.parentNetworkSiteTypeId) {
355
+ referencedTypeIds.add(
356
+ normalizeId(childType.parentNetworkSiteTypeId),
357
+ );
358
+ }
359
+ }
360
+
361
+ if (childTypes.length < REFERENCE_VALIDATION_BATCH_SIZE) {
362
+ break;
363
+ }
364
+
365
+ childSkip += childTypes.length;
366
+ }
367
+
368
+ let siteSkip: number = 0;
369
+
370
+ while (candidateIdBatch.length > 0) {
371
+ const sites: Array<NetworkSite> = await NetworkSiteService.findBy({
372
+ query: {
373
+ networkSiteTypeId: QueryHelper.any(candidateIdBatch),
374
+ },
375
+ select: { networkSiteTypeId: true },
376
+ sort: { _id: SortOrder.Ascending },
377
+ limit: REFERENCE_VALIDATION_BATCH_SIZE,
378
+ skip: siteSkip,
379
+ props: { isRoot: true },
380
+ });
381
+
382
+ for (const site of sites) {
383
+ if (site.networkSiteTypeId) {
384
+ referencedTypeIds.add(normalizeId(site.networkSiteTypeId));
385
+ }
386
+ }
387
+
388
+ if (sites.length < REFERENCE_VALIDATION_BATCH_SIZE) {
389
+ break;
390
+ }
391
+
392
+ siteSkip += sites.length;
393
+ }
394
+ }
395
+
396
+ for (const candidate of candidates) {
397
+ if (
398
+ candidate.id &&
399
+ candidate.projectId &&
400
+ !referencedTypeIds.has(normalizeId(candidate.id))
401
+ ) {
402
+ leafTypes.push(candidate);
403
+
404
+ if (leafTypes.length === requestedLimit) {
405
+ break;
406
+ }
407
+ }
408
+ }
409
+
410
+ scanSkip += candidates.length;
411
+
412
+ if (candidates.length < scanPageSize) {
413
+ break;
414
+ }
415
+ }
416
+
417
+ if (leafTypes.length === 0) {
418
+ return 0;
419
+ }
420
+
421
+ const leafTypeIds: Array<ObjectID> = leafTypes.map(
422
+ (networkSiteType: Model): ObjectID => {
423
+ return networkSiteType.id!;
424
+ },
425
+ );
426
+
427
+ return await NetworkSiteHierarchyLock.runExclusive({
428
+ projectIds: leafTypes.map((networkSiteType: Model): ObjectID => {
429
+ return networkSiteType.projectId!;
430
+ }),
431
+ operation: async (): Promise<number> => {
432
+ return await super.hardDeleteBy({
433
+ ...deleteBy,
434
+ query: {
435
+ ...deleteBy.query,
436
+ _id: QueryHelper.any(leafTypeIds),
437
+ },
438
+ limit: leafTypeIds.length,
439
+ skip: 0,
440
+ });
441
+ },
442
+ });
443
+ }
444
+
445
+ private async findMutationProjectIds(data: {
446
+ query: Query<Model>;
447
+ props: DatabaseCommonInteractionProps;
448
+ limit: number;
449
+ skip: number;
450
+ isDelete: boolean;
451
+ }): Promise<Array<ObjectID | string>> {
452
+ NetworkSiteHierarchyLock.assertSafeRootMutationScope({
453
+ query: data.query as unknown as Record<string, unknown>,
454
+ props: data.props,
455
+ tenantScopeIsClosed: data.isDelete,
456
+ });
457
+
458
+ const networkSiteTypes: Array<Model> = await this.findBy({
459
+ query: data.isDelete
460
+ ? this.scopeDeleteQueryToCallerTenant(data.query, data.props)
461
+ : this.scopeQueryToCallerTenant(data.query, data.props),
462
+ select: { projectId: true },
463
+ limit: data.limit,
464
+ skip: data.skip,
465
+ props: { isRoot: true },
466
+ });
467
+
468
+ const projectIds: Array<ObjectID | string> = networkSiteTypes
469
+ .map((networkSiteType: Model): ObjectID | undefined => {
470
+ return networkSiteType.projectId;
471
+ })
472
+ .filter((projectId: ObjectID | undefined): projectId is ObjectID => {
473
+ return Boolean(projectId);
474
+ });
475
+
476
+ projectIds.push(
477
+ ...NetworkSiteHierarchyLock.getExplicitProjectIds(
478
+ data.query as unknown as Record<string, unknown>,
479
+ ),
480
+ );
481
+
482
+ if (projectIds.length === 0 && data.props.tenantId) {
483
+ projectIds.push(data.props.tenantId);
484
+ }
485
+
486
+ const seenProjectIds: Set<string> = new Set<string>();
487
+
488
+ return projectIds.filter((projectId: ObjectID | string): boolean => {
489
+ const normalizedProjectId: string = normalizeId(projectId);
490
+
491
+ if (seenProjectIds.has(normalizedProjectId)) {
492
+ return false;
493
+ }
494
+
495
+ seenProjectIds.add(normalizedProjectId);
496
+ return true;
497
+ });
498
+ }
499
+
500
+ private scopeQueryToCallerTenant(
501
+ query: Query<Model>,
502
+ props: DatabaseCommonInteractionProps,
503
+ ): Query<Model> {
504
+ if (props.isRoot || props.isMasterAdmin || !props.tenantId) {
505
+ return query;
506
+ }
507
+
508
+ return {
509
+ ...query,
510
+ projectId: props.tenantId,
511
+ };
512
+ }
513
+
514
+ /*
515
+ * DeletePermission retains tenant scoping for root callers that provide a
516
+ * tenantId. The hierarchy preflight must select the identical window.
517
+ */
518
+ private scopeDeleteQueryToCallerTenant(
519
+ query: Query<Model>,
520
+ props: DatabaseCommonInteractionProps,
521
+ ): Query<Model> {
522
+ if (!props.tenantId || props.isMultiTenantRequest) {
523
+ return query;
524
+ }
525
+
526
+ return {
527
+ ...query,
528
+ projectId: props.tenantId,
529
+ };
530
+ }
531
+
532
+ private readProjectId(data: Record<string, unknown>): ObjectID | null {
533
+ for (const key of PROJECT_KEYS) {
534
+ const value: unknown = data[key];
535
+ const isExplicitClear: boolean = value === null || value === "";
536
+
537
+ if (typeof value === "function") {
538
+ throw new BadDataException(
539
+ `${key} cannot be set to a raw SQL expression because the Network Site Type project must be validated against an actual ID.`,
540
+ );
541
+ }
542
+
543
+ if (
544
+ value !== undefined &&
545
+ !isExplicitClear &&
546
+ !RelationIdUtil.read(data, [key])
547
+ ) {
548
+ throw new BadDataException(`${key} must contain a valid Project ID.`);
549
+ }
550
+ }
551
+
552
+ return RelationIdUtil.readConsistent(data, PROJECT_KEYS, "project");
553
+ }
554
+
555
+ /*
556
+ * Dashboard entity pickers submit the relation object; services and
557
+ * migrations usually submit the scalar FK. Validate both, and refuse a
558
+ * contradictory pair rather than relying on ORM precedence for the shared
559
+ * join column.
560
+ */
561
+ private readParentId(data: Record<string, unknown>): ObjectID | null {
562
+ assertNoSqlExpression(data, PARENT_NETWORK_SITE_TYPE_KEYS);
563
+
564
+ for (const key of PARENT_NETWORK_SITE_TYPE_KEYS) {
565
+ const value: unknown = data[key];
566
+ const isExplicitClear: boolean = value === null || value === "";
567
+
568
+ if (
569
+ value !== undefined &&
570
+ !isExplicitClear &&
571
+ !RelationIdUtil.read(data, [key])
572
+ ) {
573
+ throw new BadDataException(
574
+ `${key} must contain a valid Network Site Type ID.`,
575
+ );
576
+ }
577
+ }
578
+
579
+ return RelationIdUtil.readConsistent(
580
+ data,
581
+ PARENT_NETWORK_SITE_TYPE_KEYS,
582
+ "parent Network Site Type",
583
+ );
584
+ }
585
+
586
+ private async getNextSiblingOrder(data: {
587
+ projectId: ObjectID;
588
+ parentNetworkSiteTypeId: ObjectID | null;
589
+ }): Promise<number> {
590
+ const siblings: Array<Model> = await this.findAllNetworkSiteTypes({
591
+ query: {
592
+ projectId: data.projectId,
593
+ parentNetworkSiteTypeId: data.parentNetworkSiteTypeId
594
+ ? data.parentNetworkSiteTypeId
595
+ : QueryHelper.isNull(),
596
+ } as Query<Model>,
597
+ select: { order: true },
598
+ });
599
+
600
+ const maxOrder: number | null = siblings.reduce<number | null>(
601
+ (currentMax: number | null, sibling: Model) => {
602
+ return typeof sibling.order === "number"
603
+ ? Math.max(currentMax ?? sibling.order, sibling.order)
604
+ : currentMax;
605
+ },
606
+ null,
607
+ );
608
+
609
+ return maxOrder === null ? 1 : maxOrder + 1;
610
+ }
611
+
612
+ private async findAllNetworkSiteTypes(data: {
613
+ query: Query<Model>;
614
+ select: Select<Model>;
615
+ }): Promise<Array<Model>> {
616
+ const networkSiteTypes: Array<Model> = [];
617
+ let skip: number = 0;
618
+
619
+ while (true) {
620
+ const page: Array<Model> = await this.findBy({
621
+ query: data.query,
622
+ select: data.select,
623
+ sort: { _id: SortOrder.Ascending },
624
+ limit: LIMIT_MAX,
625
+ skip,
626
+ props: { isRoot: true },
627
+ });
628
+
629
+ networkSiteTypes.push(...page);
630
+
631
+ if (page.length < LIMIT_MAX) {
632
+ return networkSiteTypes;
633
+ }
634
+
635
+ skip += page.length;
636
+ }
637
+ }
638
+
639
+ /*
640
+ * Network estates regularly exceed LIMIT_MAX. Every hierarchy invariant is
641
+ * universal ("all sites match"), so silently validating only the first page
642
+ * would make its result depend on row order. A stable id sort also prevents
643
+ * offset pages from overlapping while these read-only checks run.
644
+ */
645
+ private async findAllNetworkSites(data: {
646
+ query: Query<NetworkSite>;
647
+ select: Select<NetworkSite>;
648
+ }): Promise<Array<NetworkSite>> {
649
+ const sites: Array<NetworkSite> = [];
650
+ let skip: number = 0;
651
+
652
+ while (true) {
653
+ const page: Array<NetworkSite> = await NetworkSiteService.findBy({
654
+ query: data.query,
655
+ select: data.select,
656
+ sort: { _id: SortOrder.Ascending },
657
+ limit: LIMIT_MAX,
658
+ skip,
659
+ props: { isRoot: true },
660
+ });
661
+
662
+ sites.push(...page);
663
+
664
+ if (page.length < LIMIT_MAX) {
665
+ return sites;
666
+ }
667
+
668
+ skip += page.length;
669
+ }
670
+ }
671
+
672
+ private async assertParentIsValid(data: {
673
+ networkSiteTypeId: ObjectID | null;
674
+ parentNetworkSiteTypeId: ObjectID;
675
+ projectId: ObjectID;
676
+ }): Promise<void> {
677
+ if (
678
+ data.networkSiteTypeId &&
679
+ sameId(data.networkSiteTypeId, data.parentNetworkSiteTypeId)
680
+ ) {
681
+ throw new BadDataException(
682
+ "A Network Site Type cannot be its own parent.",
683
+ );
684
+ }
685
+
686
+ const parent: Model | null = await this.findOneById({
687
+ id: data.parentNetworkSiteTypeId,
688
+ select: {
689
+ _id: true,
690
+ projectId: true,
691
+ isUnitLevel: true,
692
+ },
693
+ props: { isRoot: true },
694
+ });
695
+
696
+ if (!parent) {
697
+ throw new BadDataException("Parent Network Site Type not found.");
698
+ }
699
+
700
+ if (!parent.projectId || !sameId(parent.projectId, data.projectId)) {
701
+ throw new BadDataException(
702
+ "Parent Network Site Type must belong to the same project.",
703
+ );
704
+ }
705
+
706
+ if (parent.isUnitLevel === true) {
707
+ throw new BadDataException(
708
+ "A unit-level Network Site Type cannot have child types.",
709
+ );
710
+ }
711
+
712
+ if (!data.networkSiteTypeId) {
713
+ return;
714
+ }
715
+
716
+ const networkSiteTypes: Array<Model> = await this.findAllNetworkSiteTypes({
717
+ query: { projectId: data.projectId },
718
+ select: {
719
+ _id: true,
720
+ parentNetworkSiteTypeId: true,
721
+ },
722
+ });
723
+
724
+ const movingType: Model = new Model();
725
+ movingType.id = data.networkSiteTypeId;
726
+
727
+ const parentIsDescendant: boolean =
728
+ NetworkSiteTypeHierarchyUtil.getDescendantNetworkSiteTypes({
729
+ networkSiteType: movingType,
730
+ networkSiteTypes,
731
+ }).some((descendant: Model) => {
732
+ return Boolean(
733
+ descendant.id && sameId(descendant.id, data.parentNetworkSiteTypeId),
734
+ );
735
+ });
736
+
737
+ if (parentIsDescendant) {
738
+ throw new BadDataException(
739
+ "A Network Site Type cannot be moved under one of its descendants.",
740
+ );
741
+ }
742
+ }
743
+
744
+ /*
745
+ * Changing a type definition must not retroactively make the concrete site
746
+ * tree invalid. A root type may only describe root sites; a child type may
747
+ * only describe sites whose actual parent has the declared parent type.
748
+ */
749
+ private async assertExistingSitesMatchProposedParent(data: {
750
+ networkSiteTypeId: ObjectID;
751
+ proposedParentNetworkSiteTypeId: ObjectID | null;
752
+ }): Promise<void> {
753
+ const sites: Array<NetworkSite> = await this.findAllNetworkSites({
754
+ query: { networkSiteTypeId: data.networkSiteTypeId },
755
+ select: {
756
+ _id: true,
757
+ parentSiteId: true,
758
+ },
759
+ });
760
+
761
+ if (sites.length === 0) {
762
+ return;
763
+ }
764
+
765
+ if (!data.proposedParentNetworkSiteTypeId) {
766
+ if (
767
+ sites.some((site: NetworkSite) => {
768
+ return Boolean(site.parentSiteId);
769
+ })
770
+ ) {
771
+ throw new BadDataException(EXISTING_SITES_DO_NOT_MATCH_MESSAGE);
772
+ }
773
+
774
+ return;
775
+ }
776
+
777
+ const parentSiteIds: Array<ObjectID> = [];
778
+ const distinctParentSiteIds: Set<string> = new Set<string>();
779
+
780
+ for (const site of sites) {
781
+ if (!site.parentSiteId) {
782
+ throw new BadDataException(EXISTING_SITES_DO_NOT_MATCH_MESSAGE);
783
+ }
784
+
785
+ const normalizedParentSiteId: string = normalizeId(site.parentSiteId);
786
+ if (!distinctParentSiteIds.has(normalizedParentSiteId)) {
787
+ distinctParentSiteIds.add(normalizedParentSiteId);
788
+ parentSiteIds.push(site.parentSiteId);
789
+ }
790
+ }
791
+
792
+ const parentSites: Array<NetworkSite> = [];
793
+
794
+ for (
795
+ let offset: number = 0;
796
+ offset < parentSiteIds.length;
797
+ offset += LIMIT_MAX
798
+ ) {
799
+ const parentSiteIdBatch: Array<ObjectID> = parentSiteIds.slice(
800
+ offset,
801
+ offset + LIMIT_MAX,
802
+ );
803
+
804
+ parentSites.push(
805
+ ...(await this.findAllNetworkSites({
806
+ query: {
807
+ _id: QueryHelper.any(
808
+ parentSiteIdBatch.map((parentSiteId: ObjectID) => {
809
+ return parentSiteId.toString();
810
+ }),
811
+ ),
812
+ },
813
+ select: {
814
+ _id: true,
815
+ networkSiteTypeId: true,
816
+ },
817
+ })),
818
+ );
819
+ }
820
+
821
+ const parentTypeBySiteId: Map<string, ObjectID> = new Map<
822
+ string,
823
+ ObjectID
824
+ >();
825
+
826
+ for (const parentSite of parentSites) {
827
+ if (parentSite.id && parentSite.networkSiteTypeId) {
828
+ parentTypeBySiteId.set(
829
+ normalizeId(parentSite.id),
830
+ parentSite.networkSiteTypeId,
831
+ );
832
+ }
833
+ }
834
+
835
+ const hasMismatch: boolean = parentSiteIds.some(
836
+ (parentSiteId: ObjectID) => {
837
+ const actualParentTypeId: ObjectID | undefined = parentTypeBySiteId.get(
838
+ normalizeId(parentSiteId),
839
+ );
840
+
841
+ return (
842
+ !actualParentTypeId ||
843
+ !sameId(actualParentTypeId, data.proposedParentNetworkSiteTypeId!)
844
+ );
845
+ },
846
+ );
847
+
848
+ if (hasMismatch) {
849
+ throw new BadDataException(EXISTING_SITES_DO_NOT_MATCH_MESSAGE);
850
+ }
851
+ }
852
+
853
+ private async assertTypesCanBecomeUnitLevel(
854
+ networkSiteTypes: Array<Model>,
855
+ ): Promise<void> {
856
+ const networkSiteTypeIds: Array<ObjectID> = networkSiteTypes
857
+ .map((networkSiteType: Model) => {
858
+ return networkSiteType.id;
859
+ })
860
+ .filter((id: ObjectID | null): id is ObjectID => {
861
+ return Boolean(id);
862
+ });
863
+
864
+ if (networkSiteTypeIds.length === 0) {
865
+ return;
866
+ }
867
+
868
+ const projectIds: Array<string> = [
869
+ ...new Set<string>(
870
+ networkSiteTypes
871
+ .map((networkSiteType: Model) => {
872
+ return networkSiteType.projectId?.toString();
873
+ })
874
+ .filter((projectId: string | undefined): projectId is string => {
875
+ return Boolean(projectId);
876
+ }),
877
+ ),
878
+ ];
879
+
880
+ const child: Model | null = await this.findOneBy({
881
+ query: {
882
+ parentNetworkSiteTypeId: QueryHelper.any(
883
+ networkSiteTypeIds.map((id: ObjectID) => {
884
+ return id.toString();
885
+ }),
886
+ ),
887
+ ...(projectIds.length > 0
888
+ ? { projectId: QueryHelper.any(projectIds) }
889
+ : {}),
890
+ },
891
+ select: { _id: true },
892
+ props: { isRoot: true },
893
+ });
894
+
895
+ if (child) {
896
+ throw new BadDataException(
897
+ "A Network Site Type with child types cannot be made unit-level.",
898
+ );
899
+ }
900
+
901
+ const sitesOfTypes: Array<NetworkSite> = await this.findAllNetworkSites({
902
+ query: {
903
+ networkSiteTypeId: QueryHelper.any(
904
+ networkSiteTypeIds.map((id: ObjectID) => {
905
+ return id.toString();
906
+ }),
907
+ ),
908
+ },
909
+ select: { _id: true },
910
+ });
911
+
912
+ const siteIds: Array<string> = sitesOfTypes
913
+ .map((site: NetworkSite) => {
914
+ return site.id?.toString();
915
+ })
916
+ .filter((id: string | undefined): id is string => {
917
+ return Boolean(id);
918
+ });
919
+
920
+ if (siteIds.length === 0) {
921
+ return;
922
+ }
923
+
924
+ for (
925
+ let offset: number = 0;
926
+ offset < siteIds.length;
927
+ offset += REFERENCE_VALIDATION_BATCH_SIZE
928
+ ) {
929
+ const childSite: NetworkSite | null = await NetworkSiteService.findOneBy({
930
+ query: {
931
+ parentSiteId: QueryHelper.any(
932
+ siteIds.slice(offset, offset + REFERENCE_VALIDATION_BATCH_SIZE),
933
+ ),
934
+ ...(projectIds.length > 0
935
+ ? { projectId: QueryHelper.any(projectIds) }
936
+ : {}),
937
+ },
938
+ select: { _id: true },
939
+ props: { isRoot: true },
940
+ });
941
+
942
+ if (childSite) {
943
+ throw new BadDataException(
944
+ "A Network Site Type whose sites have child sites cannot be made unit-level.",
945
+ );
946
+ }
947
+ }
948
+ }
949
+
950
+ @CaptureSpan()
951
+ protected override async onBeforeCreate(
952
+ createBy: CreateBy<Model>,
953
+ ): Promise<OnCreate<Model>> {
954
+ const data: Record<string, unknown> = createBy.data as unknown as Record<
955
+ string,
956
+ unknown
957
+ >;
958
+ assertIsUnitLevelIsNotSqlExpression(data);
959
+ const parentNetworkSiteTypeId: ObjectID | null = this.readParentId(data);
960
+ const projectId: ObjectID | null =
961
+ createBy.props.tenantId || this.readProjectId(data) || null;
962
+
963
+ if (!projectId) {
964
+ throw new BadDataException("Project ID is required.");
965
+ }
966
+
967
+ if (parentNetworkSiteTypeId) {
968
+ await this.assertParentIsValid({
969
+ networkSiteTypeId: createBy.data.id,
970
+ parentNetworkSiteTypeId,
971
+ projectId,
972
+ });
973
+ }
974
+
975
+ if (createBy.data.order === undefined || createBy.data.order === null) {
976
+ createBy.data.order = await this.getNextSiblingOrder({
977
+ projectId,
978
+ parentNetworkSiteTypeId,
979
+ });
980
+ }
981
+
982
+ return { createBy, carryForward: null };
983
+ }
984
+
985
+ @CaptureSpan()
986
+ protected override async onBeforeUpdate(
987
+ updateBy: UpdateBy<Model>,
988
+ ): Promise<OnUpdate<Model>> {
989
+ const data: Record<string, unknown> = (updateBy.data ||
990
+ {}) as unknown as Record<string, unknown>;
991
+ assertIsUnitLevelIsNotSqlExpression(data);
992
+ const isParentWritten: boolean = isAnyKeyWritten(
993
+ data,
994
+ PARENT_NETWORK_SITE_TYPE_KEYS,
995
+ );
996
+ const isBecomingUnitLevel: boolean = data["isUnitLevel"] === true;
997
+ const isProjectWritten: boolean = isAnyKeyWritten(data, PROJECT_KEYS);
998
+ const proposedProjectId: ObjectID | null = isProjectWritten
999
+ ? this.readProjectId(data)
1000
+ : null;
1001
+
1002
+ if (!isParentWritten && !isBecomingUnitLevel && !isProjectWritten) {
1003
+ return { updateBy, carryForward: null };
1004
+ }
1005
+
1006
+ if (isProjectWritten && !proposedProjectId) {
1007
+ throw new BadDataException(
1008
+ "A Network Site Type cannot be moved to another project.",
1009
+ );
1010
+ }
1011
+
1012
+ const proposedParentNetworkSiteTypeId: ObjectID | null = isParentWritten
1013
+ ? this.readParentId(data)
1014
+ : null;
1015
+
1016
+ const updateLimit: number =
1017
+ updateBy.limit instanceof PositiveNumber
1018
+ ? updateBy.limit.toNumber()
1019
+ : updateBy.limit || LIMIT_MAX;
1020
+ const updateSkip: number =
1021
+ updateBy.skip instanceof PositiveNumber
1022
+ ? updateBy.skip.toNumber()
1023
+ : updateBy.skip || 0;
1024
+
1025
+ const networkSiteTypesBeingUpdated: Array<Model> = await this.findBy({
1026
+ query: this.scopeQueryToCallerTenant(updateBy.query, updateBy.props),
1027
+ select: {
1028
+ _id: true,
1029
+ projectId: true,
1030
+ parentNetworkSiteTypeId: true,
1031
+ isUnitLevel: true,
1032
+ },
1033
+ limit: updateLimit,
1034
+ skip: updateSkip,
1035
+ props: { isRoot: true },
1036
+ });
1037
+
1038
+ if (isProjectWritten) {
1039
+ for (const networkSiteType of networkSiteTypesBeingUpdated) {
1040
+ if (
1041
+ !networkSiteType.projectId ||
1042
+ !proposedProjectId ||
1043
+ !sameId(networkSiteType.projectId, proposedProjectId)
1044
+ ) {
1045
+ throw new BadDataException(
1046
+ "A Network Site Type cannot be moved to another project.",
1047
+ );
1048
+ }
1049
+ }
1050
+ }
1051
+
1052
+ if (!isParentWritten && !isBecomingUnitLevel) {
1053
+ return { updateBy, carryForward: null };
1054
+ }
1055
+
1056
+ if (isBecomingUnitLevel) {
1057
+ await this.assertTypesCanBecomeUnitLevel(
1058
+ networkSiteTypesBeingUpdated.filter((networkSiteType: Model) => {
1059
+ return networkSiteType.isUnitLevel !== true;
1060
+ }),
1061
+ );
1062
+ }
1063
+
1064
+ if (isParentWritten) {
1065
+ for (const networkSiteType of networkSiteTypesBeingUpdated) {
1066
+ if (!networkSiteType.id || !networkSiteType.projectId) {
1067
+ continue;
1068
+ }
1069
+
1070
+ if (proposedParentNetworkSiteTypeId) {
1071
+ await this.assertParentIsValid({
1072
+ networkSiteTypeId: networkSiteType.id,
1073
+ parentNetworkSiteTypeId: proposedParentNetworkSiteTypeId,
1074
+ projectId: networkSiteType.projectId,
1075
+ });
1076
+ }
1077
+
1078
+ const currentParentId: string | null =
1079
+ NetworkSiteTypeHierarchyUtil.getParentId(networkSiteType);
1080
+ const parentChanged: boolean = proposedParentNetworkSiteTypeId
1081
+ ? !currentParentId ||
1082
+ !sameId(currentParentId, proposedParentNetworkSiteTypeId)
1083
+ : Boolean(currentParentId);
1084
+
1085
+ if (parentChanged) {
1086
+ await this.assertExistingSitesMatchProposedParent({
1087
+ networkSiteTypeId: networkSiteType.id,
1088
+ proposedParentNetworkSiteTypeId,
1089
+ });
1090
+
1091
+ if (
1092
+ networkSiteTypesBeingUpdated.length === 1 &&
1093
+ data["order"] === undefined
1094
+ ) {
1095
+ updateBy.data.order = await this.getNextSiblingOrder({
1096
+ projectId: networkSiteType.projectId,
1097
+ parentNetworkSiteTypeId: proposedParentNetworkSiteTypeId,
1098
+ });
1099
+ }
1100
+ }
1101
+ }
1102
+ }
1103
+
1104
+ return { updateBy, carryForward: null };
1105
+ }
1106
+
1107
+ @CaptureSpan()
1108
+ protected override async onBeforeDelete(
1109
+ deleteBy: DeleteBy<Model>,
1110
+ ): Promise<OnDelete<Model>> {
1111
+ const deleteLimit: number =
1112
+ deleteBy.limit instanceof PositiveNumber
1113
+ ? deleteBy.limit.toNumber()
1114
+ : deleteBy.limit || LIMIT_MAX;
1115
+ const deleteSkip: number =
1116
+ deleteBy.skip instanceof PositiveNumber
1117
+ ? deleteBy.skip.toNumber()
1118
+ : deleteBy.skip || 0;
1119
+
1120
+ const networkSiteTypesBeingDeleted: Array<Model> = await this.findBy({
1121
+ query: this.scopeDeleteQueryToCallerTenant(
1122
+ deleteBy.query,
1123
+ deleteBy.props,
1124
+ ),
1125
+ select: { _id: true, projectId: true },
1126
+ limit: deleteLimit,
1127
+ skip: deleteSkip,
1128
+ props: { isRoot: true },
1129
+ });
1130
+
1131
+ const ids: Array<ObjectID> = networkSiteTypesBeingDeleted
1132
+ .map((networkSiteType: Model) => {
1133
+ return networkSiteType.id;
1134
+ })
1135
+ .filter((id: ObjectID | null): id is ObjectID => {
1136
+ return Boolean(id);
1137
+ });
1138
+
1139
+ if (ids.length === 0) {
1140
+ return { deleteBy, carryForward: null };
1141
+ }
1142
+
1143
+ const idStrings: Array<string> = ids.map((id: ObjectID) => {
1144
+ return id.toString();
1145
+ });
1146
+
1147
+ const deletingIds: Set<string> = new Set<string>(
1148
+ idStrings.map((id: string) => {
1149
+ return normalizeId(id);
1150
+ }),
1151
+ );
1152
+ const projectIdStrings: Array<string> = [
1153
+ ...new Set<string>(
1154
+ networkSiteTypesBeingDeleted
1155
+ .map((networkSiteType: Model) => {
1156
+ return networkSiteType.projectId?.toString();
1157
+ })
1158
+ .filter((projectId: string | undefined): projectId is string => {
1159
+ return Boolean(projectId);
1160
+ }),
1161
+ ),
1162
+ ];
1163
+
1164
+ for (
1165
+ let parentOffset: number = 0;
1166
+ parentOffset < idStrings.length;
1167
+ parentOffset += REFERENCE_VALIDATION_BATCH_SIZE
1168
+ ) {
1169
+ const parentIdBatch: Array<string> = idStrings.slice(
1170
+ parentOffset,
1171
+ parentOffset + REFERENCE_VALIDATION_BATCH_SIZE,
1172
+ );
1173
+ let childSkip: number = 0;
1174
+
1175
+ while (true) {
1176
+ const childTypes: Array<Model> = await this.findBy({
1177
+ query: {
1178
+ parentNetworkSiteTypeId: QueryHelper.any(parentIdBatch),
1179
+ ...(projectIdStrings.length > 0
1180
+ ? { projectId: QueryHelper.any(projectIdStrings) }
1181
+ : {}),
1182
+ },
1183
+ select: { _id: true },
1184
+ sort: { _id: SortOrder.Ascending },
1185
+ limit: REFERENCE_VALIDATION_BATCH_SIZE,
1186
+ skip: childSkip,
1187
+ props: { isRoot: true },
1188
+ });
1189
+
1190
+ const hasSurvivingChild: boolean = childTypes.some((child: Model) => {
1191
+ return !child.id || !deletingIds.has(normalizeId(child.id));
1192
+ });
1193
+
1194
+ if (hasSurvivingChild) {
1195
+ throw new BadDataException(
1196
+ "A Network Site Type cannot be deleted while child types use it as their parent.",
1197
+ );
1198
+ }
1199
+
1200
+ if (childTypes.length < REFERENCE_VALIDATION_BATCH_SIZE) {
1201
+ break;
1202
+ }
1203
+
1204
+ childSkip += childTypes.length;
1205
+ }
1206
+
1207
+ const site: NetworkSite | null = await NetworkSiteService.findOneBy({
1208
+ query: {
1209
+ networkSiteTypeId: QueryHelper.any(parentIdBatch),
1210
+ },
1211
+ select: { _id: true },
1212
+ props: { isRoot: true },
1213
+ });
1214
+
1215
+ if (site) {
1216
+ throw new BadDataException(
1217
+ "A Network Site Type cannot be deleted while Network Sites use it.",
1218
+ );
1219
+ }
1220
+ }
1221
+
1222
+ return { deleteBy, carryForward: null };
1223
+ }
8
1224
  }
9
1225
 
10
1226
  export default new Service();