@oneuptime/common 12.0.8 → 12.0.9

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 (769) hide show
  1. package/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.ts +1 -1
  2. package/Models/AnalyticsModels/MetricItemAggMV1mByService.ts +1 -1
  3. package/Models/DatabaseModels/AIConversation.ts +32 -0
  4. package/Models/DatabaseModels/AIConversationMessage.ts +41 -0
  5. package/Models/DatabaseModels/AlertEpisodeMember.ts +27 -0
  6. package/Models/DatabaseModels/IncidentEpisodeMember.ts +28 -0
  7. package/Models/DatabaseModels/Index.ts +12 -4
  8. package/Models/DatabaseModels/{TelemetryEntity.ts → InventoryItem.ts} +139 -9
  9. package/Models/DatabaseModels/InventoryItemCustomField.ts +434 -0
  10. package/Models/DatabaseModels/{TelemetryEntityRelationship.ts → InventoryItemRelationship.ts} +8 -8
  11. package/Models/DatabaseModels/NetworkDevice.ts +141 -0
  12. package/Models/DatabaseModels/NetworkDeviceLink.ts +699 -0
  13. package/Models/DatabaseModels/NetworkDeviceLinkRule.ts +467 -0
  14. package/Models/DatabaseModels/NetworkTopologySuppression.ts +429 -0
  15. package/Models/DatabaseModels/OnCallDutyPolicyFeed.ts +9 -0
  16. package/Models/DatabaseModels/Project.ts +78 -0
  17. package/Models/DatabaseModels/UserCall.ts +42 -0
  18. package/Models/DatabaseModels/UserEmail.ts +44 -0
  19. package/Models/DatabaseModels/UserNotificationRule.ts +425 -55
  20. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +24 -2
  21. package/Models/DatabaseModels/UserPush.ts +49 -0
  22. package/Models/DatabaseModels/UserSMS.ts +43 -0
  23. package/Models/DatabaseModels/UserTelegram.ts +59 -0
  24. package/Models/DatabaseModels/UserWebhook.ts +52 -0
  25. package/Models/DatabaseModels/UserWhatsApp.ts +41 -0
  26. package/Models/DatabaseModels/WorkflowVariable.ts +12 -0
  27. package/Server/API/AIChatAPI.ts +315 -1
  28. package/Server/API/DashboardAPI.ts +217 -1
  29. package/Server/API/OnCallReadinessAPI.ts +841 -0
  30. package/Server/API/TeamComplianceAPI.ts +69 -17
  31. package/Server/API/TelemetryAPI.ts +220 -12
  32. package/Server/EnvironmentConfig.ts +52 -0
  33. package/Server/Infrastructure/Postgres/DataSourceOptions.ts +22 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +4 -4
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +5 -5
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/1786625176831-AddMonitoringMethodToNetworkDevice.ts +35 -0
  37. package/Server/Infrastructure/Postgres/SchemaMigrations/1786634985763-AddNetworkDeviceLink.ts +82 -0
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/1786639512056-AddNetworkDeviceLinkRule.ts +91 -0
  39. package/Server/Infrastructure/Postgres/SchemaMigrations/1786639972982-AddNetworkTopologySuppression.ts +47 -0
  40. package/Server/Infrastructure/Postgres/SchemaMigrations/1786800000000-RenameTelemetryEntityToInventoryItem.ts +255 -0
  41. package/Server/Infrastructure/Postgres/SchemaMigrations/1786900000000-AddInventoryItemArchiveAndCustomFields.ts +107 -0
  42. package/Server/Infrastructure/Postgres/SchemaMigrations/1787000000000-AddOnCallNotificationFallbackColumns.ts +90 -0
  43. package/Server/Infrastructure/Postgres/SchemaMigrations/1787100000000-AddAIConversationPageContext.ts +39 -0
  44. package/Server/Infrastructure/Postgres/SchemaMigrations/1787200000000-AddAIChatMessageFeedback.ts +33 -0
  45. package/Server/Infrastructure/Postgres/SchemaMigrations/1787300000000-AddEpisodeMemberNotifyIndexes.ts +59 -0
  46. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
  47. package/Server/Infrastructure/Queue.ts +78 -13
  48. package/Server/Middleware/PublicDashboardRateLimit.ts +593 -0
  49. package/Server/Services/AIService.ts +7 -0
  50. package/Server/Services/AlertEpisodeStateTimelineService.ts +29 -0
  51. package/Server/Services/AlertSeverityService.ts +63 -0
  52. package/Server/Services/DashboardService.ts +9 -10
  53. package/Server/Services/DatabaseService.ts +32 -2
  54. package/Server/Services/IncidentEpisodeStateTimelineService.ts +29 -0
  55. package/Server/Services/IncidentSeverityService.ts +76 -0
  56. package/Server/Services/Index.ts +12 -4
  57. package/Server/Services/InventoryItemCustomFieldService.ts +9 -0
  58. package/Server/Services/{TelemetryEntityRelationshipService.ts → InventoryItemRelationshipService.ts} +4 -4
  59. package/Server/Services/{TelemetryEntityService.ts → InventoryItemService.ts} +89 -20
  60. package/Server/Services/LogAggregationService.ts +45 -8
  61. package/Server/Services/MetricAggregationService.ts +121 -0
  62. package/Server/Services/MetricService.ts +7 -7
  63. package/Server/Services/NetworkDeviceLinkRuleService.ts +10 -0
  64. package/Server/Services/NetworkDeviceLinkService.ts +84 -0
  65. package/Server/Services/NetworkDeviceService.ts +140 -0
  66. package/Server/Services/NetworkSiteService.ts +77 -25
  67. package/Server/Services/NetworkTopologySuppressionService.ts +84 -0
  68. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +41 -29
  69. package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +8 -0
  70. package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +62 -13
  71. package/Server/Services/OnCallDutyPolicyScheduleService.ts +61 -1
  72. package/Server/Services/OnCallNotificationAlertingService.ts +742 -0
  73. package/Server/Services/OnCallReadinessService.ts +2803 -0
  74. package/Server/Services/OnCallSetupReminderService.ts +955 -0
  75. package/Server/Services/ProfileAggregationService.ts +123 -0
  76. package/Server/Services/StatusPageService.ts +9 -10
  77. package/Server/Services/TeamComplianceService.ts +429 -252
  78. package/Server/Services/UserCallService.ts +26 -1
  79. package/Server/Services/UserEmailService.ts +26 -1
  80. package/Server/Services/UserNotificationRuleAdminService.ts +1183 -0
  81. package/Server/Services/UserNotificationRuleService.ts +3812 -333
  82. package/Server/Services/UserOnCallLogService.ts +561 -48
  83. package/Server/Services/UserPushService.ts +29 -0
  84. package/Server/Services/UserService.ts +11 -0
  85. package/Server/Services/UserSmsService.ts +26 -1
  86. package/Server/Services/UserTelegramService.ts +24 -1
  87. package/Server/Services/UserWebhookService.ts +28 -1
  88. package/Server/Services/UserWhatsAppService.ts +24 -1
  89. package/Server/Types/Database/Permissions/BasePermission.ts +19 -0
  90. package/Server/Types/Database/Permissions/CreatePermission.ts +164 -0
  91. package/Server/Types/Database/Permissions/OwnerOnlyColumnPermission.ts +340 -0
  92. package/Server/Types/Database/Permissions/QueryPermission.ts +48 -0
  93. package/Server/Types/Database/Permissions/TenantPermission.ts +8 -1
  94. package/Server/Types/Workflow/Components/API/Delete.ts +1 -1
  95. package/Server/Types/Workflow/Components/API/Get.ts +1 -1
  96. package/Server/Types/Workflow/Components/API/Patch.ts +1 -1
  97. package/Server/Types/Workflow/Components/API/Post.ts +1 -1
  98. package/Server/Types/Workflow/Components/API/Put.ts +1 -1
  99. package/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.ts +29 -5
  100. package/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.ts +18 -10
  101. package/Server/Types/Workflow/Components/BaseModel/ModelArguments.ts +55 -0
  102. package/Server/Types/Workflow/Components/Conditions/IfElse.ts +3 -17
  103. package/Server/Types/Workflow/Components/Email.ts +25 -7
  104. package/Server/Types/Workflow/Components/JavaScript.ts +10 -3
  105. package/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.ts +1 -1
  106. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +643 -48
  107. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +32 -3
  108. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +20 -6
  109. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +7 -0
  110. package/Server/Utils/AI/Toolbox/AIActionTools.ts +2 -2
  111. package/Server/Utils/AI/Toolbox/AIMetaTools.ts +863 -0
  112. package/Server/Utils/AI/Toolbox/AlertTools.ts +177 -15
  113. package/Server/Utils/AI/Toolbox/IncidentTools.ts +191 -10
  114. package/Server/Utils/AI/Toolbox/Index.ts +48 -0
  115. package/Server/Utils/AI/Toolbox/MonitorTools.ts +298 -11
  116. package/Server/Utils/AI/Toolbox/NoteWriteTools.ts +295 -0
  117. package/Server/Utils/AI/Toolbox/OnCallTools.ts +1246 -0
  118. package/Server/Utils/AI/Toolbox/RunbookTools.ts +424 -0
  119. package/Server/Utils/AI/Toolbox/SloTools.ts +456 -0
  120. package/Server/Utils/AI/Toolbox/StatusPageTools.ts +559 -0
  121. package/Server/Utils/AI/Toolbox/TeamTools.ts +327 -0
  122. package/Server/Utils/AI/Toolbox/TimelineTools.ts +615 -0
  123. package/Server/Utils/AI/Toolbox/WorkflowProbeTools.ts +664 -0
  124. package/Server/Utils/ClientIp.ts +221 -0
  125. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +47 -0
  126. package/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.ts +163 -0
  127. package/Server/Utils/Dashboard/PublicDashboardSloWidget.ts +147 -0
  128. package/Server/Utils/Express.ts +12 -17
  129. package/Server/Utils/LLM/LLMService.ts +85 -8
  130. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +204 -10
  131. package/Server/Utils/SSRFProtection.ts +98 -23
  132. package/Server/Utils/StartServer.ts +12 -3
  133. package/Server/Utils/Telemetry/EntityRegistry.ts +205 -18
  134. package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +25 -25
  135. package/Server/Utils/Telemetry/TelemetryEntity.ts +160 -52
  136. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +7 -3
  137. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +2146 -0
  138. package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +561 -0
  139. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +2470 -0
  140. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +1897 -0
  141. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3606 -0
  142. package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +784 -0
  143. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +1119 -0
  144. package/Tests/App/Dashboard/SloWidgetFetching.test.tsx +531 -0
  145. package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +1312 -0
  146. package/Tests/App/Dashboard/UserSettingsSetupChecklistPage.test.tsx +1390 -0
  147. package/Tests/Models/InventoryItemModel.test.ts +174 -0
  148. package/Tests/Models/InventoryItemNaming.test.ts +302 -0
  149. package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +437 -0
  150. package/Tests/Server/API/DashboardPublicRateLimit.test.ts +659 -0
  151. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +18 -0
  152. package/Tests/Server/API/DashboardPublicSloAPI.test.ts +880 -0
  153. package/Tests/Server/API/Helpers.ts +24 -15
  154. package/Tests/Server/API/OnCallReadinessAPI.test.ts +2680 -0
  155. package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +915 -0
  156. package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +533 -0
  157. package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +213 -0
  158. package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +432 -0
  159. package/Tests/Server/Infrastructure/Queue.test.ts +293 -0
  160. package/Tests/Server/Middleware/PublicDashboardRateLimit.test.ts +1645 -0
  161. package/Tests/Server/Services/AdminRuleEditGuards.test.ts +2848 -0
  162. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1393 -0
  163. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +1802 -0
  164. package/Tests/Server/Services/EpisodeStateTimelineNote.test.ts +304 -0
  165. package/Tests/Server/Services/InventoryItemDisplayName.test.ts +339 -0
  166. package/Tests/Server/Services/{TelemetryEntityManualCreate.test.ts → InventoryItemManualCreate.test.ts} +27 -27
  167. package/Tests/Server/Services/IpAllowlistSpoofing.test.ts +450 -0
  168. package/Tests/Server/Services/LogAggregationService.test.ts +235 -1
  169. package/Tests/Server/Services/MetricAggregationService.test.ts +231 -0
  170. package/Tests/Server/Services/MetricEntityMVKeyParity.test.ts +80 -29
  171. package/Tests/Server/Services/MetricServiceAggregate.test.ts +30 -30
  172. package/Tests/Server/Services/NetworkSiteService.test.ts +18 -3
  173. package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +1728 -0
  174. package/Tests/Server/Services/NotificationDeletionImpact.test.ts +2402 -0
  175. package/Tests/Server/Services/OnCallDutyPolicyExecutionLogTimelineGapFeed.test.ts +394 -0
  176. package/Tests/Server/Services/OnCallNotificationFallback.test.ts +1744 -0
  177. package/Tests/Server/Services/OnCallReadinessService.test.ts +4295 -0
  178. package/Tests/Server/Services/OnCallSetupReminder.test.ts +1272 -0
  179. package/Tests/Server/Services/OnCallWeeklyReadinessDigest.test.ts +1021 -0
  180. package/Tests/Server/Services/ProfileAggregationService.test.ts +296 -0
  181. package/Tests/Server/Services/SeverityCreationRuleBackfill.test.ts +1536 -0
  182. package/Tests/Server/Services/SeverityRuleBackfill.test.ts +1818 -0
  183. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +1845 -0
  184. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +1394 -0
  185. package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +1166 -0
  186. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1468 -0
  187. package/Tests/Server/Services/UserOnCallLogNoNotificationRules.test.ts +1457 -0
  188. package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +1546 -0
  189. package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +529 -0
  190. package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +1219 -0
  191. package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +1089 -0
  192. package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +2 -1
  193. package/Tests/Server/Types/Workflow/Components/BaseModelDatabaseComponents.test.ts +190 -0
  194. package/Tests/Server/Types/Workflow/Components/ChatWebhookComponents.test.ts +44 -14
  195. package/Tests/Server/Types/Workflow/Components/Email.test.ts +151 -0
  196. package/Tests/Server/Types/Workflow/Components/IfElse.test.ts +98 -0
  197. package/Tests/Server/Types/Workflow/Components/JavaScript.test.ts +51 -0
  198. package/Tests/Server/Utils/AI/AIMetaTools.test.ts +586 -0
  199. package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +582 -0
  200. package/Tests/Server/Utils/AI/ChatAgentRunner.test.ts +726 -0
  201. package/Tests/Server/Utils/AI/IncidentToolsFilters.test.ts +315 -0
  202. package/Tests/Server/Utils/AI/LLMServiceStopReason.test.ts +314 -0
  203. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +26 -3
  204. package/Tests/Server/Utils/AI/NoteWriteTools.test.ts +268 -0
  205. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +169 -0
  206. package/Tests/Server/Utils/AI/OnCallTools.test.ts +664 -0
  207. package/Tests/Server/Utils/AI/RunbookTools.test.ts +325 -0
  208. package/Tests/Server/Utils/AI/SloTools.test.ts +306 -0
  209. package/Tests/Server/Utils/AI/StatusPageTools.test.ts +391 -0
  210. package/Tests/Server/Utils/AI/TeamTools.test.ts +257 -0
  211. package/Tests/Server/Utils/AI/TimelineTools.test.ts +472 -0
  212. package/Tests/Server/Utils/AI/WorkflowProbeTools.test.ts +428 -0
  213. package/Tests/Server/Utils/ClientIp.test.ts +438 -0
  214. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +171 -0
  215. package/Tests/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.test.ts +383 -0
  216. package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +23 -25
  217. package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +6 -0
  218. package/Tests/Server/Utils/Monitor/Criteria/DnssecMonitorCriteria.test.ts +307 -0
  219. package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +468 -0
  220. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorTelemetryDeepLinks.test.ts +460 -0
  221. package/Tests/Server/Utils/ResponseRateLimitStatusCodes.test.ts +137 -0
  222. package/Tests/Server/Utils/SSRFProtectionBypasses.test.ts +40 -8
  223. package/Tests/Server/Utils/SSRFProtectionUserInfo.test.ts +351 -0
  224. package/Tests/Server/Utils/Telemetry/EntityRegistryRetirement.test.ts +531 -0
  225. package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +15 -15
  226. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +356 -39
  227. package/Tests/Types/IP/IP.test.ts +263 -0
  228. package/Tests/Types/IP/IPWhitelist.test.ts +197 -0
  229. package/Tests/Types/IP/IPv6.test.ts +12 -1
  230. package/Tests/Types/Monitor/SnmpOid.test.ts +64 -0
  231. package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +110 -0
  232. package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeAudit.test.ts +106 -0
  233. package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeDifferential.test.ts +511 -0
  234. package/Tests/Types/OnCallDutyPolicy/ScheduleCoverageEndToEnd.test.ts +489 -0
  235. package/Tests/Types/OnCallDutyPolicy/ScheduleCoverageGapTolerance.test.ts +479 -0
  236. package/Tests/Types/OnCallDutyPolicy/ScheduleCoverageState.test.ts +822 -0
  237. package/Tests/Types/Telemetry/EntityTypeGroups.test.ts +6 -6
  238. package/Tests/Types/Workflow/BaseModelComponents.test.ts +429 -0
  239. package/Tests/Types/Workflow/Components/BaseModel.test.ts +225 -0
  240. package/Tests/Types/Workflow/IntegrationCredentialMetadata.test.ts +100 -0
  241. package/Tests/Types/Workflow/TemplateSyntax.test.ts +112 -0
  242. package/Tests/Types/Workflow/Templates.test.ts +916 -101
  243. package/Tests/UI/Components/ActiveFilterChipsOpenRoute.test.tsx +82 -0
  244. package/Tests/UI/Components/ComponentsModal.test.tsx +564 -7
  245. package/Tests/UI/Components/KeyboardShortcut.test.tsx +95 -0
  246. package/Tests/UI/Components/LogDetailsPanelCrossSignal.test.tsx +448 -0
  247. package/Tests/UI/Components/LogsTableCrossLinks.test.tsx +263 -0
  248. package/Tests/UI/Components/PendingProjectInvitations.test.tsx +913 -0
  249. package/Tests/UI/Components/SimpleLogViewer.test.tsx +228 -0
  250. package/Tests/UI/Components/TableRowSelectability.test.tsx +312 -0
  251. package/Tests/UI/Components/Workflow/GraphLint.test.ts +72 -0
  252. package/Tests/UI/Components/Workflow/GraphLintSummary.test.ts +755 -0
  253. package/Tests/UI/Components/Workflow/ModelColumnEditor.test.ts +242 -7
  254. package/Tests/UI/Components/Workflow/ModelColumnEditorServerContract.test.ts +15 -7
  255. package/Tests/UI/Components/Workflow/ModelSchema.test.ts +242 -28
  256. package/Tests/UI/Components/Workflow/RunStatusWatcher.test.ts +59 -1
  257. package/Tests/UI/Components/Workflow/StepTraceViewer.test.tsx +256 -0
  258. package/Tests/UI/Components/Workflow/UseRunWatch.test.tsx +665 -0
  259. package/Tests/UI/Components/Workflow/WorkflowIssuesModal.test.tsx +485 -0
  260. package/Tests/UI/Components/Workflow/WorkflowLogModal.test.tsx +478 -0
  261. package/Tests/UI/Components/Workflow/WorkflowStatusBar.test.tsx +379 -0
  262. package/Tests/UI/EsbuildConfig.test.ts +607 -0
  263. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +5 -0
  264. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +11 -4
  265. package/Tests/UI/Utils/ModelAPICreateMiscData.test.ts +94 -0
  266. package/Tests/UI/Utils/Platform.test.ts +147 -0
  267. package/Tests/UI/Utils/ProjectInvitationDisplay.test.ts +357 -0
  268. package/Tests/Utils/Monitor/NetworkDeviceLinkRuleUtil.test.ts +198 -0
  269. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +487 -0
  270. package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +698 -0
  271. package/Tests/__mocks__/bullmq.js +55 -0
  272. package/Types/AI/AIChatMessageStatus.ts +8 -1
  273. package/Types/AI/AIChatTypes.ts +12 -0
  274. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +88 -0
  275. package/Types/Exception/ExceptionCode.ts +2 -0
  276. package/Types/Exception/ServiceUnavailableException.ts +8 -0
  277. package/Types/Exception/TooManyRequestsException.ts +8 -0
  278. package/Types/IP/IP.ts +93 -47
  279. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +49 -3
  280. package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +55 -0
  281. package/Types/OnCallDutyPolicy/Layer.ts +203 -149
  282. package/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.ts +13 -0
  283. package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +155 -10
  284. package/Types/Permission.ts +193 -0
  285. package/Types/Telemetry/EntityRelationshipType.ts +1 -1
  286. package/Types/Telemetry/EntitySource.ts +1 -1
  287. package/Types/Telemetry/EntityType.ts +1 -1
  288. package/Types/Telemetry/EntityTypeGroups.ts +1 -1
  289. package/Types/Workflow/Components/BaseModel.ts +75 -29
  290. package/Types/Workflow/Components/Discord.ts +1 -0
  291. package/Types/Workflow/Components/Email.ts +12 -3
  292. package/Types/Workflow/Components/JavaScript.ts +7 -0
  293. package/Types/Workflow/Components/MicrosoftTeams.ts +3 -2
  294. package/Types/Workflow/Components/Slack.ts +1 -0
  295. package/Types/Workflow/Components/Telegram.ts +1 -0
  296. package/Types/Workflow/TemplateSyntax.ts +44 -0
  297. package/Types/Workflow/Templates.ts +2097 -45
  298. package/UI/Components/Calendar/Calendar.css +43 -0
  299. package/UI/Components/Calendar/Calendar.tsx +8 -0
  300. package/UI/Components/Card/Card.tsx +2 -2
  301. package/UI/Components/Checkbox/Checkbox.tsx +16 -0
  302. package/UI/Components/Dictionary/Dictionary.tsx +48 -9
  303. package/UI/Components/FormModal/BasicFormModal.tsx +2 -1
  304. package/UI/Components/Header/HeaderIconDropdownButton.tsx +53 -3
  305. package/UI/Components/Input/Input.tsx +1 -0
  306. package/UI/Components/KeyboardShortcut/KeyboardKey.ts +185 -0
  307. package/UI/Components/KeyboardShortcut/KeyboardShortcut.tsx +87 -0
  308. package/UI/Components/LogsViewer/LogsViewer.tsx +28 -0
  309. package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +31 -0
  310. package/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.tsx +18 -18
  311. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +363 -14
  312. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +11 -0
  313. package/UI/Components/LogsViewer/components/LogsTable.tsx +155 -12
  314. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +29 -0
  315. package/UI/Components/LogsViewer/types.ts +23 -0
  316. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +9 -2
  317. package/UI/Components/Navbar/NavBarMenuModal.tsx +15 -30
  318. package/UI/Components/ProjectInvitations/PendingProjectInvitations.tsx +442 -0
  319. package/UI/Components/SimpleLogViewer/SimpleLogViewer.tsx +23 -1
  320. package/UI/Components/Table/Table.tsx +49 -16
  321. package/UI/Components/Table/TableBody.tsx +53 -28
  322. package/UI/Components/Table/TableHeader.tsx +13 -0
  323. package/UI/Components/Table/TableRow.tsx +58 -26
  324. package/UI/Components/Workflow/ArgumentsForm.tsx +155 -9
  325. package/UI/Components/Workflow/ComponentReturnValueViewer.tsx +26 -0
  326. package/UI/Components/Workflow/ComponentSettingsModal.tsx +10 -1
  327. package/UI/Components/Workflow/ComponentValuePickerModal.tsx +135 -7
  328. package/UI/Components/Workflow/ComponentsModal.tsx +116 -22
  329. package/UI/Components/Workflow/DocumentationViewer.tsx +59 -9
  330. package/UI/Components/Workflow/GraphLint.ts +42 -5
  331. package/UI/Components/Workflow/GraphLintSummary.ts +390 -0
  332. package/UI/Components/Workflow/ModelColumnEditor.tsx +154 -22
  333. package/UI/Components/Workflow/ModelSchema.ts +115 -33
  334. package/UI/Components/Workflow/RunStatusWatcher.ts +1 -1
  335. package/UI/Components/Workflow/StepTraceViewer.tsx +1 -1
  336. package/UI/Components/Workflow/UseRunWatch.ts +212 -0
  337. package/UI/Components/Workflow/VariableModal.tsx +6 -2
  338. package/UI/Components/Workflow/Workflow.tsx +49 -3
  339. package/UI/Components/Workflow/WorkflowIssuesModal.tsx +255 -0
  340. package/UI/Components/Workflow/WorkflowLogModal.tsx +128 -0
  341. package/UI/Components/Workflow/WorkflowStatusBar.tsx +224 -0
  342. package/UI/Utils/AIChatExport/ConversationMarkdown.ts +10 -0
  343. package/UI/Utils/ModelAPI/ModelAPI.ts +7 -1
  344. package/UI/Utils/Platform.ts +149 -0
  345. package/UI/Utils/ProjectInvitationDisplay.ts +118 -0
  346. package/UI/esbuild-config.js +22 -1
  347. package/Utils/Monitor/NetworkDeviceLinkRuleUtil.ts +187 -0
  348. package/Utils/Monitor/NetworkTopologyUtil.ts +888 -164
  349. package/Utils/Telemetry/CrossSignalScope.ts +502 -0
  350. package/Utils/Telemetry/EntityKey.ts +5 -5
  351. package/Utils/Telemetry/EntityRelationship.ts +1 -1
  352. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js +1 -1
  353. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js +1 -1
  354. package/build/dist/Models/DatabaseModels/AIConversation.js +32 -0
  355. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
  356. package/build/dist/Models/DatabaseModels/AIConversationMessage.js +42 -0
  357. package/build/dist/Models/DatabaseModels/AIConversationMessage.js.map +1 -1
  358. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +28 -0
  359. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -1
  360. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +29 -0
  361. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -1
  362. package/build/dist/Models/DatabaseModels/Index.js +12 -4
  363. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  364. package/build/dist/Models/DatabaseModels/{TelemetryEntity.js → InventoryItem.js} +167 -31
  365. package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -0
  366. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js +454 -0
  367. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js.map +1 -0
  368. package/build/dist/Models/DatabaseModels/{TelemetryEntityRelationship.js → InventoryItemRelationship.js} +27 -27
  369. package/build/dist/Models/DatabaseModels/InventoryItemRelationship.js.map +1 -0
  370. package/build/dist/Models/DatabaseModels/NetworkDevice.js +141 -0
  371. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  372. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +719 -0
  373. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -0
  374. package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js +475 -0
  375. package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js.map +1 -0
  376. package/build/dist/Models/DatabaseModels/NetworkTopologySuppression.js +446 -0
  377. package/build/dist/Models/DatabaseModels/NetworkTopologySuppression.js.map +1 -0
  378. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyFeed.js +9 -0
  379. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyFeed.js.map +1 -1
  380. package/build/dist/Models/DatabaseModels/Project.js +80 -0
  381. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  382. package/build/dist/Models/DatabaseModels/UserCall.js +46 -2
  383. package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
  384. package/build/dist/Models/DatabaseModels/UserEmail.js +48 -2
  385. package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
  386. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +424 -55
  387. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  388. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +24 -2
  389. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  390. package/build/dist/Models/DatabaseModels/UserPush.js +51 -1
  391. package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
  392. package/build/dist/Models/DatabaseModels/UserSMS.js +47 -2
  393. package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
  394. package/build/dist/Models/DatabaseModels/UserTelegram.js +65 -3
  395. package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
  396. package/build/dist/Models/DatabaseModels/UserWebhook.js +56 -2
  397. package/build/dist/Models/DatabaseModels/UserWebhook.js.map +1 -1
  398. package/build/dist/Models/DatabaseModels/UserWhatsApp.js +45 -2
  399. package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
  400. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +12 -0
  401. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  402. package/build/dist/Server/API/AIChatAPI.js +237 -1
  403. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  404. package/build/dist/Server/API/DashboardAPI.js +165 -13
  405. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  406. package/build/dist/Server/API/OnCallReadinessAPI.js +599 -0
  407. package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -0
  408. package/build/dist/Server/API/TeamComplianceAPI.js +68 -9
  409. package/build/dist/Server/API/TeamComplianceAPI.js.map +1 -1
  410. package/build/dist/Server/API/TelemetryAPI.js +129 -18
  411. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  412. package/build/dist/Server/EnvironmentConfig.js +45 -0
  413. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  414. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +22 -0
  415. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
  416. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +4 -4
  417. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786625176831-AddMonitoringMethodToNetworkDevice.js +18 -0
  418. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786625176831-AddMonitoringMethodToNetworkDevice.js.map +1 -0
  419. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786634985763-AddNetworkDeviceLink.js +39 -0
  420. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786634985763-AddNetworkDeviceLink.js.map +1 -0
  421. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639512056-AddNetworkDeviceLinkRule.js +38 -0
  422. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639512056-AddNetworkDeviceLinkRule.js.map +1 -0
  423. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639972982-AddNetworkTopologySuppression.js +22 -0
  424. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639972982-AddNetworkTopologySuppression.js.map +1 -0
  425. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786800000000-RenameTelemetryEntityToInventoryItem.js +150 -0
  426. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786800000000-RenameTelemetryEntityToInventoryItem.js.map +1 -0
  427. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786900000000-AddInventoryItemArchiveAndCustomFields.js +57 -0
  428. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786900000000-AddInventoryItemArchiveAndCustomFields.js.map +1 -0
  429. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787000000000-AddOnCallNotificationFallbackColumns.js +69 -0
  430. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787000000000-AddOnCallNotificationFallbackColumns.js.map +1 -0
  431. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787100000000-AddAIConversationPageContext.js +32 -0
  432. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787100000000-AddAIConversationPageContext.js.map +1 -0
  433. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787200000000-AddAIChatMessageFeedback.js +26 -0
  434. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787200000000-AddAIChatMessageFeedback.js.map +1 -0
  435. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787300000000-AddEpisodeMemberNotifyIndexes.js +48 -0
  436. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787300000000-AddEpisodeMemberNotifyIndexes.js.map +1 -0
  437. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
  438. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  439. package/build/dist/Server/Infrastructure/Queue.js +72 -13
  440. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  441. package/build/dist/Server/Middleware/PublicDashboardRateLimit.js +399 -0
  442. package/build/dist/Server/Middleware/PublicDashboardRateLimit.js.map +1 -0
  443. package/build/dist/Server/Services/AIService.js +1 -0
  444. package/build/dist/Server/Services/AIService.js.map +1 -1
  445. package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js +24 -3
  446. package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js.map +1 -1
  447. package/build/dist/Server/Services/AlertSeverityService.js +54 -0
  448. package/build/dist/Server/Services/AlertSeverityService.js.map +1 -1
  449. package/build/dist/Server/Services/DashboardService.js +10 -9
  450. package/build/dist/Server/Services/DashboardService.js.map +1 -1
  451. package/build/dist/Server/Services/DatabaseService.js +24 -2
  452. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  453. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +24 -3
  454. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  455. package/build/dist/Server/Services/IncidentSeverityService.js +67 -0
  456. package/build/dist/Server/Services/IncidentSeverityService.js.map +1 -1
  457. package/build/dist/Server/Services/Index.js +12 -4
  458. package/build/dist/Server/Services/Index.js.map +1 -1
  459. package/build/dist/Server/Services/InventoryItemCustomFieldService.js +9 -0
  460. package/build/dist/Server/Services/InventoryItemCustomFieldService.js.map +1 -0
  461. package/build/dist/Server/Services/{TelemetryEntityRelationshipService.js → InventoryItemRelationshipService.js} +6 -6
  462. package/build/dist/Server/Services/InventoryItemRelationshipService.js.map +1 -0
  463. package/build/dist/Server/Services/{TelemetryEntityService.js → InventoryItemService.js} +68 -23
  464. package/build/dist/Server/Services/InventoryItemService.js.map +1 -0
  465. package/build/dist/Server/Services/LogAggregationService.js +27 -8
  466. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  467. package/build/dist/Server/Services/MetricAggregationService.js +80 -0
  468. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  469. package/build/dist/Server/Services/MetricService.js +6 -6
  470. package/build/dist/Server/Services/MetricService.js.map +1 -1
  471. package/build/dist/Server/Services/NetworkDeviceLinkRuleService.js +9 -0
  472. package/build/dist/Server/Services/NetworkDeviceLinkRuleService.js.map +1 -0
  473. package/build/dist/Server/Services/NetworkDeviceLinkService.js +71 -0
  474. package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -0
  475. package/build/dist/Server/Services/NetworkDeviceService.js +113 -0
  476. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  477. package/build/dist/Server/Services/NetworkSiteService.js +53 -13
  478. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  479. package/build/dist/Server/Services/NetworkTopologySuppressionService.js +85 -0
  480. package/build/dist/Server/Services/NetworkTopologySuppressionService.js.map +1 -0
  481. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +48 -32
  482. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  483. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +8 -0
  484. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
  485. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +51 -12
  486. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
  487. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +57 -13
  488. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  489. package/build/dist/Server/Services/OnCallNotificationAlertingService.js +548 -0
  490. package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -0
  491. package/build/dist/Server/Services/OnCallReadinessService.js +1961 -0
  492. package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -0
  493. package/build/dist/Server/Services/OnCallSetupReminderService.js +738 -0
  494. package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -0
  495. package/build/dist/Server/Services/ProfileAggregationService.js +68 -4
  496. package/build/dist/Server/Services/ProfileAggregationService.js.map +1 -1
  497. package/build/dist/Server/Services/StatusPageService.js +11 -10
  498. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  499. package/build/dist/Server/Services/TeamComplianceService.js +312 -160
  500. package/build/dist/Server/Services/TeamComplianceService.js.map +1 -1
  501. package/build/dist/Server/Services/UserCallService.js +24 -1
  502. package/build/dist/Server/Services/UserCallService.js.map +1 -1
  503. package/build/dist/Server/Services/UserEmailService.js +24 -1
  504. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  505. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +858 -0
  506. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -0
  507. package/build/dist/Server/Services/UserNotificationRuleService.js +2830 -175
  508. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  509. package/build/dist/Server/Services/UserOnCallLogService.js +488 -43
  510. package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
  511. package/build/dist/Server/Services/UserPushService.js +26 -0
  512. package/build/dist/Server/Services/UserPushService.js.map +1 -1
  513. package/build/dist/Server/Services/UserService.js +10 -0
  514. package/build/dist/Server/Services/UserService.js.map +1 -1
  515. package/build/dist/Server/Services/UserSmsService.js +24 -1
  516. package/build/dist/Server/Services/UserSmsService.js.map +1 -1
  517. package/build/dist/Server/Services/UserTelegramService.js +22 -1
  518. package/build/dist/Server/Services/UserTelegramService.js.map +1 -1
  519. package/build/dist/Server/Services/UserWebhookService.js +25 -1
  520. package/build/dist/Server/Services/UserWebhookService.js.map +1 -1
  521. package/build/dist/Server/Services/UserWhatsAppService.js +22 -1
  522. package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
  523. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +12 -1
  524. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  525. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +126 -0
  526. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  527. package/build/dist/Server/Types/Database/Permissions/OwnerOnlyColumnPermission.js +254 -0
  528. package/build/dist/Server/Types/Database/Permissions/OwnerOnlyColumnPermission.js.map +1 -0
  529. package/build/dist/Server/Types/Database/Permissions/QueryPermission.js +47 -2
  530. package/build/dist/Server/Types/Database/Permissions/QueryPermission.js.map +1 -1
  531. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +7 -0
  532. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
  533. package/build/dist/Server/Types/Workflow/Components/API/Delete.js +1 -1
  534. package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
  535. package/build/dist/Server/Types/Workflow/Components/API/Get.js +1 -1
  536. package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
  537. package/build/dist/Server/Types/Workflow/Components/API/Patch.js +1 -1
  538. package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
  539. package/build/dist/Server/Types/Workflow/Components/API/Post.js +1 -1
  540. package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
  541. package/build/dist/Server/Types/Workflow/Components/API/Put.js +1 -1
  542. package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
  543. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js +21 -5
  544. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js.map +1 -1
  545. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js +14 -10
  546. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js.map +1 -1
  547. package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js +31 -0
  548. package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js.map +1 -1
  549. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js +3 -9
  550. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js.map +1 -1
  551. package/build/dist/Server/Types/Workflow/Components/Email.js +15 -4
  552. package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
  553. package/build/dist/Server/Types/Workflow/Components/JavaScript.js +7 -2
  554. package/build/dist/Server/Types/Workflow/Components/JavaScript.js.map +1 -1
  555. package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js +1 -1
  556. package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js.map +1 -1
  557. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +514 -56
  558. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  559. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +20 -3
  560. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  561. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +19 -6
  562. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  563. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +7 -0
  564. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  565. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js +2 -2
  566. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -1
  567. package/build/dist/Server/Utils/AI/Toolbox/AIMetaTools.js +692 -0
  568. package/build/dist/Server/Utils/AI/Toolbox/AIMetaTools.js.map +1 -0
  569. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +148 -12
  570. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
  571. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +157 -10
  572. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -1
  573. package/build/dist/Server/Utils/AI/Toolbox/Index.js +37 -0
  574. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  575. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js +259 -14
  576. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js.map +1 -1
  577. package/build/dist/Server/Utils/AI/Toolbox/NoteWriteTools.js +235 -0
  578. package/build/dist/Server/Utils/AI/Toolbox/NoteWriteTools.js.map +1 -0
  579. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +1000 -0
  580. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -0
  581. package/build/dist/Server/Utils/AI/Toolbox/RunbookTools.js +356 -0
  582. package/build/dist/Server/Utils/AI/Toolbox/RunbookTools.js.map +1 -0
  583. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +394 -0
  584. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -0
  585. package/build/dist/Server/Utils/AI/Toolbox/StatusPageTools.js +465 -0
  586. package/build/dist/Server/Utils/AI/Toolbox/StatusPageTools.js.map +1 -0
  587. package/build/dist/Server/Utils/AI/Toolbox/TeamTools.js +280 -0
  588. package/build/dist/Server/Utils/AI/Toolbox/TeamTools.js.map +1 -0
  589. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js +527 -0
  590. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js.map +1 -0
  591. package/build/dist/Server/Utils/AI/Toolbox/WorkflowProbeTools.js +548 -0
  592. package/build/dist/Server/Utils/AI/Toolbox/WorkflowProbeTools.js.map +1 -0
  593. package/build/dist/Server/Utils/ClientIp.js +137 -0
  594. package/build/dist/Server/Utils/ClientIp.js.map +1 -0
  595. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +38 -0
  596. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
  597. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js +89 -0
  598. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js.map +1 -0
  599. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js +77 -0
  600. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js.map +1 -0
  601. package/build/dist/Server/Utils/Express.js +12 -12
  602. package/build/dist/Server/Utils/Express.js.map +1 -1
  603. package/build/dist/Server/Utils/LLM/LLMService.js +70 -7
  604. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  605. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +121 -11
  606. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  607. package/build/dist/Server/Utils/SSRFProtection.js +82 -21
  608. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  609. package/build/dist/Server/Utils/StartServer.js +12 -4
  610. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  611. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +165 -18
  612. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  613. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +11 -11
  614. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
  615. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +122 -47
  616. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  617. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +7 -3
  618. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  619. package/build/dist/Types/AI/AIChatMessageStatus.js +8 -1
  620. package/build/dist/Types/AI/AIChatMessageStatus.js.map +1 -1
  621. package/build/dist/Types/AI/AIChatTypes.js +12 -0
  622. package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
  623. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +60 -0
  624. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -0
  625. package/build/dist/Types/Exception/ExceptionCode.js +2 -0
  626. package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
  627. package/build/dist/Types/Exception/ServiceUnavailableException.js +8 -0
  628. package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -0
  629. package/build/dist/Types/Exception/TooManyRequestsException.js +8 -0
  630. package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -0
  631. package/build/dist/Types/IP/IP.js +87 -43
  632. package/build/dist/Types/IP/IP.js.map +1 -1
  633. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +50 -0
  634. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -0
  635. package/build/dist/Types/OnCallDutyPolicy/Layer.js +186 -123
  636. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  637. package/build/dist/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.js +13 -0
  638. package/build/dist/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.js.map +1 -1
  639. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +105 -11
  640. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
  641. package/build/dist/Types/Permission.js +174 -0
  642. package/build/dist/Types/Permission.js.map +1 -1
  643. package/build/dist/Types/Telemetry/EntityRelationshipType.js +1 -1
  644. package/build/dist/Types/Telemetry/EntitySource.js +1 -1
  645. package/build/dist/Types/Telemetry/EntityType.js +1 -1
  646. package/build/dist/Types/Telemetry/EntityTypeGroups.js +1 -1
  647. package/build/dist/Types/Telemetry/EntityTypeGroups.js.map +1 -1
  648. package/build/dist/Types/Workflow/Components/BaseModel.js +66 -28
  649. package/build/dist/Types/Workflow/Components/BaseModel.js.map +1 -1
  650. package/build/dist/Types/Workflow/Components/Discord.js +1 -0
  651. package/build/dist/Types/Workflow/Components/Discord.js.map +1 -1
  652. package/build/dist/Types/Workflow/Components/Email.js +12 -3
  653. package/build/dist/Types/Workflow/Components/Email.js.map +1 -1
  654. package/build/dist/Types/Workflow/Components/JavaScript.js +7 -0
  655. package/build/dist/Types/Workflow/Components/JavaScript.js.map +1 -1
  656. package/build/dist/Types/Workflow/Components/MicrosoftTeams.js +3 -2
  657. package/build/dist/Types/Workflow/Components/MicrosoftTeams.js.map +1 -1
  658. package/build/dist/Types/Workflow/Components/Slack.js +1 -0
  659. package/build/dist/Types/Workflow/Components/Slack.js.map +1 -1
  660. package/build/dist/Types/Workflow/Components/Telegram.js +1 -0
  661. package/build/dist/Types/Workflow/Components/Telegram.js.map +1 -1
  662. package/build/dist/Types/Workflow/TemplateSyntax.js +12 -0
  663. package/build/dist/Types/Workflow/TemplateSyntax.js.map +1 -1
  664. package/build/dist/Types/Workflow/Templates.js +1931 -38
  665. package/build/dist/Types/Workflow/Templates.js.map +1 -1
  666. package/build/dist/UI/Components/Calendar/Calendar.js +1 -1
  667. package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
  668. package/build/dist/UI/Components/Checkbox/Checkbox.js +1 -1
  669. package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
  670. package/build/dist/UI/Components/Dictionary/Dictionary.js +25 -11
  671. package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
  672. package/build/dist/UI/Components/FormModal/BasicFormModal.js.map +1 -1
  673. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +27 -4
  674. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  675. package/build/dist/UI/Components/Input/Input.js +1 -0
  676. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  677. package/build/dist/UI/Components/KeyboardShortcut/KeyboardKey.js +163 -0
  678. package/build/dist/UI/Components/KeyboardShortcut/KeyboardKey.js.map +1 -0
  679. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcut.js +47 -0
  680. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcut.js.map +1 -0
  681. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +4 -4
  682. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  683. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +11 -1
  684. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
  685. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js +10 -8
  686. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js.map +1 -1
  687. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +227 -14
  688. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  689. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +5 -0
  690. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  691. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +69 -5
  692. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
  693. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +8 -0
  694. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  695. package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
  696. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +9 -2
  697. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
  698. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +8 -21
  699. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  700. package/build/dist/UI/Components/ProjectInvitations/PendingProjectInvitations.js +251 -0
  701. package/build/dist/UI/Components/ProjectInvitations/PendingProjectInvitations.js.map +1 -0
  702. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js +9 -2
  703. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js.map +1 -1
  704. package/build/dist/UI/Components/Table/Table.js +27 -15
  705. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  706. package/build/dist/UI/Components/Table/TableBody.js +24 -18
  707. package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
  708. package/build/dist/UI/Components/Table/TableHeader.js +9 -1
  709. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  710. package/build/dist/UI/Components/Table/TableRow.js +29 -21
  711. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  712. package/build/dist/UI/Components/Workflow/ArgumentsForm.js +130 -12
  713. package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
  714. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js +10 -1
  715. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js.map +1 -1
  716. package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js +4 -4
  717. package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js.map +1 -1
  718. package/build/dist/UI/Components/Workflow/ComponentValuePickerModal.js +57 -7
  719. package/build/dist/UI/Components/Workflow/ComponentValuePickerModal.js.map +1 -1
  720. package/build/dist/UI/Components/Workflow/ComponentsModal.js +53 -18
  721. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  722. package/build/dist/UI/Components/Workflow/DocumentationViewer.js +19 -6
  723. package/build/dist/UI/Components/Workflow/DocumentationViewer.js.map +1 -1
  724. package/build/dist/UI/Components/Workflow/GraphLint.js +33 -4
  725. package/build/dist/UI/Components/Workflow/GraphLint.js.map +1 -1
  726. package/build/dist/UI/Components/Workflow/GraphLintSummary.js +231 -0
  727. package/build/dist/UI/Components/Workflow/GraphLintSummary.js.map +1 -0
  728. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +116 -21
  729. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
  730. package/build/dist/UI/Components/Workflow/ModelSchema.js +72 -34
  731. package/build/dist/UI/Components/Workflow/ModelSchema.js.map +1 -1
  732. package/build/dist/UI/Components/Workflow/RunStatusWatcher.js +1 -1
  733. package/build/dist/UI/Components/Workflow/RunStatusWatcher.js.map +1 -1
  734. package/build/dist/UI/Components/Workflow/StepTraceViewer.js +1 -1
  735. package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -1
  736. package/build/dist/UI/Components/Workflow/UseRunWatch.js +123 -0
  737. package/build/dist/UI/Components/Workflow/UseRunWatch.js.map +1 -0
  738. package/build/dist/UI/Components/Workflow/VariableModal.js +3 -2
  739. package/build/dist/UI/Components/Workflow/VariableModal.js.map +1 -1
  740. package/build/dist/UI/Components/Workflow/Workflow.js +41 -1
  741. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  742. package/build/dist/UI/Components/Workflow/WorkflowIssuesModal.js +99 -0
  743. package/build/dist/UI/Components/Workflow/WorkflowIssuesModal.js.map +1 -0
  744. package/build/dist/UI/Components/Workflow/WorkflowLogModal.js +56 -0
  745. package/build/dist/UI/Components/Workflow/WorkflowLogModal.js.map +1 -0
  746. package/build/dist/UI/Components/Workflow/WorkflowStatusBar.js +92 -0
  747. package/build/dist/UI/Components/Workflow/WorkflowStatusBar.js.map +1 -0
  748. package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js +9 -0
  749. package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js.map +1 -1
  750. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +1 -1
  751. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  752. package/build/dist/UI/Utils/Platform.js +118 -0
  753. package/build/dist/UI/Utils/Platform.js.map +1 -0
  754. package/build/dist/UI/Utils/ProjectInvitationDisplay.js +106 -0
  755. package/build/dist/UI/Utils/ProjectInvitationDisplay.js.map +1 -0
  756. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js +108 -0
  757. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js.map +1 -0
  758. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +642 -136
  759. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  760. package/build/dist/Utils/Telemetry/CrossSignalScope.js +328 -0
  761. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -0
  762. package/build/dist/Utils/Telemetry/EntityKey.js +5 -5
  763. package/build/dist/Utils/Telemetry/EntityRelationship.js +1 -1
  764. package/jest.config.json +1 -0
  765. package/package.json +1 -1
  766. package/build/dist/Models/DatabaseModels/TelemetryEntity.js.map +0 -1
  767. package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js.map +0 -1
  768. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +0 -1
  769. package/build/dist/Server/Services/TelemetryEntityService.js.map +0 -1
@@ -1,5 +1,29 @@
1
1
  import { normalizeMac } from "./EndpointAttachmentUtil";
2
2
  import { classifyDeviceRole, classifyEndpointRole, } from "./NetworkDeviceRoleUtil";
3
+ const MATCH_KEY_KINDS_STRONGEST_FIRST = [
4
+ "name",
5
+ "serial",
6
+ "mac",
7
+ "shortHost",
8
+ ];
9
+ /*
10
+ * The kinds strong enough to say "these two reports describe one peer".
11
+ *
12
+ * shortHost is excluded on purpose: `sw01.site-a` and `sw01.site-b` share
13
+ * one, and merging those would invent a device nobody owns. Against a
14
+ * MANAGED device the same key is safe, because a key two devices both
15
+ * claim is dropped from the index entirely rather than guessed at.
16
+ */
17
+ const PEER_IDENTITY_KINDS = new Set([
18
+ "name",
19
+ "serial",
20
+ "mac",
21
+ ]);
22
+ /*
23
+ * Hoisted so the literal is not the object of a member expression, which
24
+ * `wrap-regex` and Prettier cannot agree on.
25
+ */
26
+ const IPV4_PATTERN = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
3
27
  // A device not seen within this window is treated as not currently up.
4
28
  const FRESH_WINDOW_MS = 15 * 60 * 1000;
5
29
  // Endpoint nodes rendered per graph; the slice is deterministic (by MAC).
@@ -7,9 +31,11 @@ const ENDPOINT_RENDER_CAP = 2000;
7
31
  export default class NetworkTopologyUtil {
8
32
  /*
9
33
  * Builds the topology graph from every device in a project. Nodes are the
10
- * devices; LLDP and CDP neighbors that match another device (by sysName,
11
- * hostname or name) become edges, and neighbors that match nothing become
12
- * lightweight "unmanaged" nodes so links don't dead-end. Edges are
34
+ * devices; LLDP and CDP neighbors that match another device (by name,
35
+ * serial, interface MAC or FQDN short form see MatchKeyKind) become
36
+ * edges, and neighbors that match nothing become lightweight "unmanaged"
37
+ * nodes so links don't dead-end. Reports that share an identity-grade
38
+ * alias are one unmanaged node, however many switches saw it. Edges are
13
39
  * undirected and deduplicated — a link reported from both ends, or by
14
40
  * both protocols, appears once with the union of what each report knew
15
41
  * (ports, protocols, per-end interface state). When `interfaces` rows are
@@ -19,15 +45,32 @@ export default class NetworkTopologyUtil {
19
45
  * "endpoint" node linked by an "fdb" edge (capped, deterministic by MAC);
20
46
  * the rest are dropped and counted in droppedEndpointCount.
21
47
  */
22
- static buildTopology(devices, now, interfaces = [], endpoints = []) {
48
+ static buildTopology(devices, now, interfaces = [], endpoints = [], manualLinks = [], suppressedNodeKeys = new Set()) {
49
+ var _a;
23
50
  const nodes = [];
24
- // Index managed devices by the identifiers neighbor entries reference.
51
+ /*
52
+ * Index managed devices by every identifier a neighbor entry could
53
+ * reference. A key TWO devices both claim is deleted rather than
54
+ * resolved: last-writer-wins would quietly draw the link to whichever
55
+ * device happened to be indexed second, and a wrong cable on a network
56
+ * map is worse than a missing one.
57
+ */
25
58
  const deviceByMatchKey = new Map();
59
+ const ambiguousMatchKeyIds = new Set();
26
60
  for (const device of devices) {
27
61
  for (const key of NetworkTopologyUtil.matchKeysForDevice(device)) {
28
- deviceByMatchKey.set(key, device);
62
+ const keyId = NetworkTopologyUtil.matchKeyId(key);
63
+ const existing = deviceByMatchKey.get(keyId);
64
+ if (existing && existing.id !== device.id) {
65
+ ambiguousMatchKeyIds.add(keyId);
66
+ continue;
67
+ }
68
+ deviceByMatchKey.set(keyId, device);
29
69
  }
30
70
  }
71
+ for (const keyId of ambiguousMatchKeyIds) {
72
+ deviceByMatchKey.delete(keyId);
73
+ }
31
74
  // Index interface rows by (device, index) and by (device, name).
32
75
  const interfaceByDeviceAndIndex = new Map();
33
76
  const interfaceByDeviceAndName = new Map();
@@ -38,7 +81,10 @@ export default class NetworkTopologyUtil {
38
81
  interfaceByDeviceAndName.set(`${row.networkDeviceId}::${nameKey}`, row);
39
82
  }
40
83
  }
84
+ // Kept aside so the diagnostics pass below can read it back per node.
85
+ const isNeighborDiscoveryEnabledById = new Map();
41
86
  for (const device of devices) {
87
+ isNeighborDiscoveryEnabledById.set(device.id, device.isNeighborDiscoveryEnabled);
42
88
  nodes.push({
43
89
  id: device.id,
44
90
  name: device.name,
@@ -60,142 +106,242 @@ export default class NetworkTopologyUtil {
60
106
  deviceModel: device.deviceModel,
61
107
  });
62
108
  }
63
- const unmanagedNodeById = new Map();
64
109
  const edgeByKey = new Map();
110
+ /*
111
+ * Resolve every neighbor report before drawing anything.
112
+ *
113
+ * A managed match is decidable from one report, but the IDENTITY of an
114
+ * unmanaged peer is not: the switch at one end may know its neighbor's
115
+ * sysName while the switch at the other end knows only its chassis MAC,
116
+ * and only the whole set of reports says those two describe one box.
117
+ */
118
+ const resolvedClaims = [];
65
119
  for (const device of devices) {
66
120
  for (const claim of NetworkTopologyUtil.neighborClaimsForDevice(device)) {
67
- if (!claim.matchKey) {
121
+ const candidates = NetworkTopologyUtil.candidateKeysForClaim(claim);
122
+ if (candidates.length === 0) {
68
123
  continue;
69
124
  }
70
- const matched = deviceByMatchKey.get(claim.matchKey);
71
- let toNodeId;
125
+ // Candidates arrive strongest-first, so the first hit is the best one.
126
+ let matched = undefined;
127
+ for (const candidate of candidates) {
128
+ matched = deviceByMatchKey.get(NetworkTopologyUtil.matchKeyId(candidate));
129
+ if (matched) {
130
+ break;
131
+ }
132
+ }
72
133
  if (matched) {
73
134
  if (matched.id === device.id) {
74
135
  // Self-referential neighbor entry; skip.
75
136
  continue;
76
137
  }
77
- toNodeId = matched.id;
78
- }
79
- else {
80
- toNodeId = `unmanaged:${claim.matchKey}`;
81
- const existingUnmanaged = unmanagedNodeById.get(toNodeId);
82
- if (!existingUnmanaged) {
83
- const unmanagedName = claim.displayName || "Unknown device";
84
- const unmanagedNode = {
85
- id: toNodeId,
86
- name: unmanagedName,
87
- isManaged: false,
88
- kind: "unmanaged",
89
- role: classifyDeviceRole({
90
- platform: claim.remotePlatform,
91
- name: unmanagedName,
92
- }),
93
- status: "unknown",
94
- deviceModel: claim.remotePlatform,
95
- };
96
- unmanagedNodeById.set(toNodeId, unmanagedNode);
97
- nodes.push(unmanagedNode);
98
- }
99
- else if (!existingUnmanaged.deviceModel && claim.remotePlatform) {
100
- /*
101
- * A later CDP claim may know the platform the first one didn't
102
- * — which is usually the only evidence a peer's role rests on,
103
- * so the role is re-derived rather than left at whatever the
104
- * name alone produced.
105
- */
106
- existingUnmanaged.deviceModel = claim.remotePlatform;
107
- existingUnmanaged.role = classifyDeviceRole({
108
- platform: claim.remotePlatform,
109
- name: existingUnmanaged.name,
110
- });
111
- }
112
- }
113
- // The reporting device's own end, enriched from its interface row.
114
- let localEndpoint = undefined;
115
- let localPortLabel = undefined;
116
- if (claim.localInterfaceIndex !== undefined) {
117
- const localInterface = interfaceByDeviceAndIndex.get(`${device.id}::${claim.localInterfaceIndex}`);
118
- localEndpoint = {
119
- interfaceIndex: claim.localInterfaceIndex,
120
- interfaceName: localInterface === null || localInterface === void 0 ? void 0 : localInterface.name,
121
- isOperationallyUp: localInterface === null || localInterface === void 0 ? void 0 : localInterface.isOperationallyUp,
122
- isAdministrativelyUp: localInterface === null || localInterface === void 0 ? void 0 : localInterface.isAdministrativelyUp,
123
- utilizationPercent: localInterface === null || localInterface === void 0 ? void 0 : localInterface.utilizationPercent,
124
- inRateMbps: localInterface === null || localInterface === void 0 ? void 0 : localInterface.inRateMbps,
125
- outRateMbps: localInterface === null || localInterface === void 0 ? void 0 : localInterface.outRateMbps,
126
- errorsPerSecond: localInterface === null || localInterface === void 0 ? void 0 : localInterface.errorsPerSecond,
127
- };
128
- localPortLabel =
129
- (localInterface === null || localInterface === void 0 ? void 0 : localInterface.name) || `if${claim.localInterfaceIndex}`;
130
- }
131
- /*
132
- * The far end: best-effort — the advertised remote port id often
133
- * matches the remote device's interface name (e.g. "GigabitEthernet
134
- * 0/1"). Only attach data when it does; a bare port id string stays
135
- * in toPort.
136
- */
137
- let remoteEndpoint = undefined;
138
- if (matched && claim.remotePortId) {
139
- const remotePortKey = NetworkTopologyUtil.normalizeKey(claim.remotePortId);
140
- const remoteInterface = remotePortKey
141
- ? interfaceByDeviceAndName.get(`${matched.id}::${remotePortKey}`)
142
- : undefined;
143
- if (remoteInterface) {
144
- remoteEndpoint = {
145
- interfaceIndex: remoteInterface.interfaceIndex,
146
- interfaceName: remoteInterface.name,
147
- isOperationallyUp: remoteInterface.isOperationallyUp,
148
- isAdministrativelyUp: remoteInterface.isAdministrativelyUp,
149
- utilizationPercent: remoteInterface.utilizationPercent,
150
- inRateMbps: remoteInterface.inRateMbps,
151
- outRateMbps: remoteInterface.outRateMbps,
152
- errorsPerSecond: remoteInterface.errorsPerSecond,
153
- };
154
- }
155
- }
156
- // Undirected dedupe: canonicalize the endpoint pair.
157
- const edgeKey = [device.id, toNodeId].sort().join("::");
158
- const existing = edgeByKey.get(edgeKey);
159
- if (!existing) {
160
- edgeByKey.set(edgeKey, {
161
- fromNodeId: device.id,
162
- toNodeId: toNodeId,
163
- fromPort: localPortLabel,
164
- toPort: claim.remotePortId,
165
- protocols: [claim.protocol],
166
- fromInterface: localEndpoint,
167
- toInterface: remoteEndpoint,
138
+ resolvedClaims.push({
139
+ device: device,
140
+ claim: claim,
141
+ matchedDeviceId: matched.id,
142
+ peerAliases: [],
168
143
  });
169
144
  continue;
170
145
  }
171
- /*
172
- * Same link reported again — from the other end, or by the other
173
- * protocol. Merge instead of dropping so both ends keep the best
174
- * data anyone reported about them.
175
- */
176
- if (existing.protocols &&
177
- !existing.protocols.includes(claim.protocol)) {
178
- existing.protocols.push(claim.protocol);
179
- }
180
- if (existing.fromNodeId === device.id) {
181
- existing.fromPort = existing.fromPort || localPortLabel;
182
- existing.toPort = existing.toPort || claim.remotePortId;
183
- existing.fromInterface = NetworkTopologyUtil.mergeEndpoints(existing.fromInterface, localEndpoint);
184
- existing.toInterface = NetworkTopologyUtil.mergeEndpoints(existing.toInterface, remoteEndpoint);
185
- }
186
- else {
187
- existing.toPort = existing.toPort || localPortLabel;
188
- existing.fromPort = existing.fromPort || claim.remotePortId;
189
- existing.toInterface = NetworkTopologyUtil.mergeEndpoints(existing.toInterface, localEndpoint);
190
- existing.fromInterface = NetworkTopologyUtil.mergeEndpoints(existing.fromInterface, remoteEndpoint);
146
+ resolvedClaims.push({
147
+ device: device,
148
+ claim: claim,
149
+ matchedDeviceId: undefined,
150
+ peerAliases: candidates.filter((candidate) => {
151
+ return PEER_IDENTITY_KINDS.has(candidate.kind);
152
+ }),
153
+ });
154
+ }
155
+ }
156
+ const peerNodeIdByClaim = NetworkTopologyUtil.buildUnmanagedPeerNodes(resolvedClaims, nodes);
157
+ for (const resolved of resolvedClaims) {
158
+ const device = resolved.device;
159
+ const claim = resolved.claim;
160
+ const matchedId = resolved.matchedDeviceId;
161
+ const toNodeId = matchedId || peerNodeIdByClaim.get(resolved);
162
+ if (!toNodeId) {
163
+ continue;
164
+ }
165
+ // The reporting device's own end, enriched from its interface row.
166
+ let localEndpoint = undefined;
167
+ let localPortLabel = undefined;
168
+ if (claim.localInterfaceIndex !== undefined) {
169
+ const localInterface = interfaceByDeviceAndIndex.get(`${device.id}::${claim.localInterfaceIndex}`);
170
+ localEndpoint = {
171
+ interfaceIndex: claim.localInterfaceIndex,
172
+ interfaceName: localInterface === null || localInterface === void 0 ? void 0 : localInterface.name,
173
+ isOperationallyUp: localInterface === null || localInterface === void 0 ? void 0 : localInterface.isOperationallyUp,
174
+ isAdministrativelyUp: localInterface === null || localInterface === void 0 ? void 0 : localInterface.isAdministrativelyUp,
175
+ utilizationPercent: localInterface === null || localInterface === void 0 ? void 0 : localInterface.utilizationPercent,
176
+ inRateMbps: localInterface === null || localInterface === void 0 ? void 0 : localInterface.inRateMbps,
177
+ outRateMbps: localInterface === null || localInterface === void 0 ? void 0 : localInterface.outRateMbps,
178
+ errorsPerSecond: localInterface === null || localInterface === void 0 ? void 0 : localInterface.errorsPerSecond,
179
+ };
180
+ localPortLabel =
181
+ (localInterface === null || localInterface === void 0 ? void 0 : localInterface.name) || `if${claim.localInterfaceIndex}`;
182
+ }
183
+ /*
184
+ * The far end: best-effort — the advertised remote port id often
185
+ * matches the remote device's interface name (e.g. "GigabitEthernet
186
+ * 0/1"). Only attach data when it does; a bare port id string stays
187
+ * in toPort.
188
+ */
189
+ let remoteEndpoint = undefined;
190
+ if (matchedId && claim.remotePortId) {
191
+ const remotePortKey = NetworkTopologyUtil.normalizeKey(claim.remotePortId);
192
+ const remoteInterface = remotePortKey
193
+ ? interfaceByDeviceAndName.get(`${matchedId}::${remotePortKey}`)
194
+ : undefined;
195
+ if (remoteInterface) {
196
+ remoteEndpoint = {
197
+ interfaceIndex: remoteInterface.interfaceIndex,
198
+ interfaceName: remoteInterface.name,
199
+ isOperationallyUp: remoteInterface.isOperationallyUp,
200
+ isAdministrativelyUp: remoteInterface.isAdministrativelyUp,
201
+ utilizationPercent: remoteInterface.utilizationPercent,
202
+ inRateMbps: remoteInterface.inRateMbps,
203
+ outRateMbps: remoteInterface.outRateMbps,
204
+ errorsPerSecond: remoteInterface.errorsPerSecond,
205
+ };
191
206
  }
192
207
  }
208
+ // Undirected dedupe: canonicalize the endpoint pair.
209
+ const edgeKey = [device.id, toNodeId].sort().join("::");
210
+ const existing = edgeByKey.get(edgeKey);
211
+ if (!existing) {
212
+ edgeByKey.set(edgeKey, {
213
+ fromNodeId: device.id,
214
+ toNodeId: toNodeId,
215
+ fromPort: localPortLabel,
216
+ toPort: claim.remotePortId,
217
+ protocols: [claim.protocol],
218
+ fromInterface: localEndpoint,
219
+ toInterface: remoteEndpoint,
220
+ });
221
+ continue;
222
+ }
223
+ /*
224
+ * Same link reported again — from the other end, or by the other
225
+ * protocol. Merge instead of dropping so both ends keep the best
226
+ * data anyone reported about them.
227
+ */
228
+ if (existing.protocols && !existing.protocols.includes(claim.protocol)) {
229
+ existing.protocols.push(claim.protocol);
230
+ }
231
+ if (existing.fromNodeId === device.id) {
232
+ existing.fromPort = existing.fromPort || localPortLabel;
233
+ existing.toPort = existing.toPort || claim.remotePortId;
234
+ existing.fromInterface = NetworkTopologyUtil.mergeEndpoints(existing.fromInterface, localEndpoint);
235
+ existing.toInterface = NetworkTopologyUtil.mergeEndpoints(existing.toInterface, remoteEndpoint);
236
+ }
237
+ else {
238
+ existing.toPort = existing.toPort || localPortLabel;
239
+ existing.fromPort = existing.fromPort || claim.remotePortId;
240
+ existing.toInterface = NetworkTopologyUtil.mergeEndpoints(existing.toInterface, localEndpoint);
241
+ existing.fromInterface = NetworkTopologyUtil.mergeEndpoints(existing.fromInterface, remoteEndpoint);
242
+ }
193
243
  }
194
- const edges = Array.from(edgeByKey.values());
195
- // --- Endpoint nodes + fdb edges ---
196
244
  const deviceNodeIds = new Set(devices.map((device) => {
197
245
  return device.id;
198
246
  }));
247
+ /*
248
+ * --- Operator-declared links ---
249
+ *
250
+ * Merged into the SAME edge map the discovery protocols write to, so a
251
+ * cable somebody drew by hand and the same cable LLDP later reports are
252
+ * one line carrying both protocols — not two lines between one pair of
253
+ * boxes, which is exactly the duplicate an operator would read as a
254
+ * second physical link.
255
+ *
256
+ * Ends outside this graph are skipped rather than drawn: a link to a
257
+ * device in another site (or one since archived) has nothing to attach
258
+ * to here.
259
+ */
260
+ for (const link of manualLinks) {
261
+ if (!deviceNodeIds.has(link.fromDeviceId) ||
262
+ !deviceNodeIds.has(link.toDeviceId) ||
263
+ link.fromDeviceId === link.toDeviceId) {
264
+ continue;
265
+ }
266
+ const edgeKey = [link.fromDeviceId, link.toDeviceId]
267
+ .sort()
268
+ .join("::");
269
+ const existing = edgeByKey.get(edgeKey);
270
+ if (!existing) {
271
+ edgeByKey.set(edgeKey, {
272
+ fromNodeId: link.fromDeviceId,
273
+ toNodeId: link.toDeviceId,
274
+ fromPort: link.fromPortName,
275
+ toPort: link.toPortName,
276
+ protocols: ["manual"],
277
+ monitorState: link.monitorStatus,
278
+ name: link.name,
279
+ });
280
+ continue;
281
+ }
282
+ if (existing.protocols && !existing.protocols.includes("manual")) {
283
+ existing.protocols.push("manual");
284
+ }
285
+ /*
286
+ * Discovered data wins on the shared fields — it is measured, and the
287
+ * hand-typed port is a best recollection. The operator's name and the
288
+ * monitor's verdict have no discovered counterpart, so they always
289
+ * apply.
290
+ */
291
+ if (existing.fromNodeId === link.fromDeviceId) {
292
+ existing.fromPort = existing.fromPort || link.fromPortName;
293
+ existing.toPort = existing.toPort || link.toPortName;
294
+ }
295
+ else {
296
+ existing.toPort = existing.toPort || link.fromPortName;
297
+ existing.fromPort = existing.fromPort || link.toPortName;
298
+ }
299
+ existing.name = existing.name || link.name;
300
+ existing.monitorState = (_a = existing.monitorState) !== null && _a !== void 0 ? _a : link.monitorStatus;
301
+ }
302
+ const edges = Array.from(edgeByKey.values());
303
+ /*
304
+ * --- Why a device has no links ---
305
+ *
306
+ * Attached to every managed node, so the detail panel can answer "the
307
+ * router is not linked to anything" with a cause instead of a shrug.
308
+ * Built from the claims that were just resolved: the unmatched ones are
309
+ * the actionable evidence — a renamed peer, a device nobody has added
310
+ * yet — and they are otherwise thrown away here.
311
+ */
312
+ const reportedNeighborCountByDeviceId = new Map();
313
+ const unmatchedIdentifiersByDeviceId = new Map();
314
+ for (const resolved of resolvedClaims) {
315
+ const deviceId = resolved.device.id;
316
+ reportedNeighborCountByDeviceId.set(deviceId, (reportedNeighborCountByDeviceId.get(deviceId) || 0) + 1);
317
+ if (resolved.matchedDeviceId) {
318
+ continue;
319
+ }
320
+ const identifier = resolved.claim.displayName || resolved.claim.identifiers[0];
321
+ if (!identifier) {
322
+ continue;
323
+ }
324
+ const bucket = unmatchedIdentifiersByDeviceId.get(deviceId);
325
+ if (bucket) {
326
+ if (!bucket.includes(identifier)) {
327
+ bucket.push(identifier);
328
+ }
329
+ }
330
+ else {
331
+ unmatchedIdentifiersByDeviceId.set(deviceId, [identifier]);
332
+ }
333
+ }
334
+ for (const node of nodes) {
335
+ if (node.kind !== "device") {
336
+ continue;
337
+ }
338
+ node.diagnostics = {
339
+ isNeighborDiscoveryEnabled: isNeighborDiscoveryEnabledById.get(node.id),
340
+ reportedNeighborCount: reportedNeighborCountByDeviceId.get(node.id) || 0,
341
+ unmatchedNeighborIdentifiers: unmatchedIdentifiersByDeviceId.get(node.id) || [],
342
+ };
343
+ }
344
+ // --- Endpoint nodes + fdb edges ---
199
345
  /*
200
346
  * Deterministic render order: by normalized MAC, then id, so the capped
201
347
  * slice is stable across rebuilds regardless of query order.
@@ -273,11 +419,39 @@ export default class NetworkTopologyUtil {
273
419
  : undefined,
274
420
  });
275
421
  }
422
+ /*
423
+ * --- Hidden nodes ---
424
+ *
425
+ * Applied last, on the finished graph, so a suppressed node cannot
426
+ * change how anything else resolved. Hiding a switch must not silently
427
+ * re-route its neighbours' links or turn its peers into strangers — it
428
+ * takes the box off the map and nothing more. Its edges go with it,
429
+ * because a line to a node that is not drawn is a line into empty space.
430
+ */
431
+ if (suppressedNodeKeys.size === 0) {
432
+ return {
433
+ nodes,
434
+ edges,
435
+ droppedEndpointCount,
436
+ endpointsTruncated,
437
+ suppressedNodeCount: 0,
438
+ };
439
+ }
440
+ const visibleNodes = nodes.filter((node) => {
441
+ return !suppressedNodeKeys.has(node.id);
442
+ });
443
+ const visibleNodeIds = new Set(visibleNodes.map((node) => {
444
+ return node.id;
445
+ }));
276
446
  return {
277
- nodes,
278
- edges,
447
+ nodes: visibleNodes,
448
+ edges: edges.filter((edge) => {
449
+ return (visibleNodeIds.has(edge.fromNodeId) &&
450
+ visibleNodeIds.has(edge.toNodeId));
451
+ }),
279
452
  droppedEndpointCount,
280
453
  endpointsTruncated,
454
+ suppressedNodeCount: nodes.length - visibleNodes.length,
281
455
  };
282
456
  }
283
457
  /*
@@ -288,11 +462,25 @@ export default class NetworkTopologyUtil {
288
462
  static neighborClaimsForDevice(device) {
289
463
  const claims = [];
290
464
  for (const neighbor of device.lldpNeighbors || []) {
465
+ /*
466
+ * Both identifiers are carried, not just the first non-empty one.
467
+ * The chassis id used to be a fallback that only applied when the
468
+ * peer advertised no sysName; it is in fact an identifier in its own
469
+ * right — a MAC or a serial — and the device it names is very often
470
+ * one we already manage.
471
+ */
472
+ const identifiers = [];
473
+ if (neighbor.remoteSysName) {
474
+ identifiers.push(neighbor.remoteSysName);
475
+ }
476
+ if (neighbor.remoteChassisId) {
477
+ identifiers.push(neighbor.remoteChassisId);
478
+ }
291
479
  claims.push({
292
480
  protocol: "lldp",
293
- matchKey: NetworkTopologyUtil.normalizeKey(neighbor.remoteSysName) ||
294
- NetworkTopologyUtil.normalizeKey(neighbor.remoteChassisId),
481
+ identifiers: identifiers,
295
482
  displayName: neighbor.remoteSysName || neighbor.remoteChassisId,
483
+ hasAdvertisedName: Boolean(neighbor.remoteSysName),
296
484
  localInterfaceIndex: neighbor.localInterfaceIndex,
297
485
  remotePortId: neighbor.remotePortId,
298
486
  remotePlatform: undefined,
@@ -301,8 +489,9 @@ export default class NetworkTopologyUtil {
301
489
  for (const neighbor of device.cdpNeighbors || []) {
302
490
  claims.push({
303
491
  protocol: "cdp",
304
- matchKey: NetworkTopologyUtil.normalizeKey(neighbor.remoteDeviceId),
492
+ identifiers: neighbor.remoteDeviceId ? [neighbor.remoteDeviceId] : [],
305
493
  displayName: neighbor.remoteDeviceId,
494
+ hasAdvertisedName: Boolean(neighbor.remoteDeviceId),
306
495
  localInterfaceIndex: neighbor.localInterfaceIndex,
307
496
  remotePortId: neighbor.remotePortId,
308
497
  remotePlatform: neighbor.remotePlatform,
@@ -310,6 +499,84 @@ export default class NetworkTopologyUtil {
310
499
  }
311
500
  return claims;
312
501
  }
502
+ /*
503
+ * Every key a claim could be resolved by, strongest kind first and, within
504
+ * a kind, strongest SOURCE first (an advertised sysName ahead of a chassis
505
+ * id). Sorting by kind before source is deliberate: a MAC read off a
506
+ * chassis id identifies a box far more precisely than the first label of
507
+ * somebody's FQDN, whichever field it arrived in.
508
+ */
509
+ static candidateKeysForClaim(claim) {
510
+ const byKind = new Map();
511
+ const seen = new Set();
512
+ for (const identifier of claim.identifiers) {
513
+ for (const key of NetworkTopologyUtil.candidateKeysForIdentifier(identifier)) {
514
+ const keyId = NetworkTopologyUtil.matchKeyId(key);
515
+ if (seen.has(keyId)) {
516
+ continue;
517
+ }
518
+ seen.add(keyId);
519
+ const bucket = byKind.get(key.kind);
520
+ if (bucket) {
521
+ bucket.push(key);
522
+ }
523
+ else {
524
+ byKind.set(key.kind, [key]);
525
+ }
526
+ }
527
+ }
528
+ const ordered = [];
529
+ for (const kind of MATCH_KEY_KINDS_STRONGEST_FIRST) {
530
+ ordered.push(...(byKind.get(kind) || []));
531
+ }
532
+ return ordered;
533
+ }
534
+ /*
535
+ * One identifier string, offered as every kind it could be.
536
+ *
537
+ * A chassis id is just bytes on the wire — nothing in the protocol says
538
+ * whether it is a name, a serial or a MAC — so it is offered as all of
539
+ * them, and only a key some device actually published can match.
540
+ */
541
+ static candidateKeysForIdentifier(raw) {
542
+ const normalized = NetworkTopologyUtil.normalizeKey(raw);
543
+ if (!normalized) {
544
+ return [];
545
+ }
546
+ const keys = [
547
+ { kind: "name", value: normalized },
548
+ { kind: "serial", value: normalized },
549
+ ];
550
+ const mac = normalizeMac(normalized);
551
+ if (mac) {
552
+ keys.push({ kind: "mac", value: mac });
553
+ }
554
+ const shortHost = NetworkTopologyUtil.shortHostKey(normalized);
555
+ if (shortHost) {
556
+ keys.push({ kind: "shortHost", value: shortHost });
557
+ }
558
+ return keys;
559
+ }
560
+ /*
561
+ * The first label of a hostname, or undefined when taking one would be
562
+ * nonsense. An IPv4 literal would shorten to "10" and a MAC to its first
563
+ * octet pair — both of which would collide half the estate into one node,
564
+ * so both are refused outright.
565
+ */
566
+ static shortHostKey(normalized) {
567
+ if (IPV4_PATTERN.test(normalized) || normalizeMac(normalized)) {
568
+ return undefined;
569
+ }
570
+ const firstLabel = normalized.split(".")[0] || "";
571
+ return firstLabel.length > 0 ? firstLabel : undefined;
572
+ }
573
+ static matchKeyId(key) {
574
+ /*
575
+ * A NUL separator, because every kind shares one namespace and a
576
+ * hostname may legitimately contain a colon-ish character.
577
+ */
578
+ return `${key.kind}\u0000${key.value}`;
579
+ }
313
580
  // Existing fields win; the incoming report only fills what's missing.
314
581
  static mergeEndpoints(existing, incoming) {
315
582
  var _a, _b, _c, _d, _e, _f, _g, _h;
@@ -330,21 +597,251 @@ export default class NetworkTopologyUtil {
330
597
  errorsPerSecond: (_h = existing.errorsPerSecond) !== null && _h !== void 0 ? _h : incoming.errorsPerSecond,
331
598
  };
332
599
  }
600
+ /*
601
+ * Every key this device answers to.
602
+ *
603
+ * Unlike a claim's candidates, these are NOT speculative: we know which
604
+ * column each value came from, so a serial is only ever registered as a
605
+ * serial. That asymmetry is the whole point — a claim may offer its
606
+ * chassis id as a name, a serial and a MAC, but only the kind a device
607
+ * actually published can be the one that matches.
608
+ */
333
609
  static matchKeysForDevice(device) {
334
- /*
335
- * sysName / hostname / name — the identifiers LLDP remoteSysName and
336
- * CDP remoteDeviceId advertise. Order matters only across devices
337
- * (last writer wins on a collision), not within one device.
338
- */
339
610
  const keys = [];
611
+ const seen = new Set();
612
+ const add = (key) => {
613
+ const keyId = NetworkTopologyUtil.matchKeyId(key);
614
+ if (seen.has(keyId)) {
615
+ return;
616
+ }
617
+ seen.add(keyId);
618
+ keys.push(key);
619
+ };
620
+ // sysName / hostname / name — what both protocols advertise.
340
621
  for (const candidate of [device.sysName, device.hostname, device.name]) {
341
- const key = NetworkTopologyUtil.normalizeKey(candidate);
342
- if (key && !keys.includes(key)) {
343
- keys.push(key);
622
+ const normalized = NetworkTopologyUtil.normalizeKey(candidate);
623
+ if (!normalized) {
624
+ continue;
625
+ }
626
+ add({ kind: "name", value: normalized });
627
+ /*
628
+ * The short form is registered for EVERY name, dotted or not, so the
629
+ * two halves of the comparison meet: an FQDN on the wire has to be
630
+ * able to find a bare sysName here, and a bare name on the wire has
631
+ * to be able to find an FQDN.
632
+ */
633
+ const shortHost = NetworkTopologyUtil.shortHostKey(normalized);
634
+ if (shortHost) {
635
+ add({ kind: "shortHost", value: shortHost });
636
+ }
637
+ }
638
+ const serial = NetworkTopologyUtil.normalizeKey(device.serialNumber);
639
+ if (serial) {
640
+ add({ kind: "serial", value: serial });
641
+ }
642
+ for (const rawMac of device.macAddresses || []) {
643
+ const mac = normalizeMac(rawMac);
644
+ if (mac) {
645
+ add({ kind: "mac", value: mac });
344
646
  }
345
647
  }
346
648
  return keys;
347
649
  }
650
+ /*
651
+ * Turns the unmatched claims into unmanaged peer NODES, one per box.
652
+ *
653
+ * Reports are merged when they share any identity-grade alias, so the
654
+ * neighbor one switch knows as "ap-lobby" and another knows only by its
655
+ * chassis MAC lands on a single node instead of the two strangers the map
656
+ * used to draw. Appends the nodes it mints to `nodes` and returns the node
657
+ * id each claim should draw its edge to.
658
+ */
659
+ static buildUnmanagedPeerNodes(resolvedClaims, nodes) {
660
+ const unmanagedClaims = resolvedClaims.filter((resolved) => {
661
+ return !resolved.matchedDeviceId && resolved.peerAliases.length > 0;
662
+ });
663
+ const rootByAliasId = NetworkTopologyUtil.groupPeerAliases(unmanagedClaims);
664
+ // Claims per peer, in first-encounter order so the output is stable.
665
+ const claimsByRoot = new Map();
666
+ for (const resolved of unmanagedClaims) {
667
+ const root = rootByAliasId.get(NetworkTopologyUtil.matchKeyId(resolved.peerAliases[0]));
668
+ if (!root) {
669
+ continue;
670
+ }
671
+ const bucket = claimsByRoot.get(root);
672
+ if (bucket) {
673
+ bucket.push(resolved);
674
+ }
675
+ else {
676
+ claimsByRoot.set(root, [resolved]);
677
+ }
678
+ }
679
+ const nodeIdByClaim = new Map();
680
+ const usedNodeIds = new Set();
681
+ for (const groupClaims of claimsByRoot.values()) {
682
+ /*
683
+ * The nicest label anyone reported: a name the peer advertises about
684
+ * itself beats a bare chassis id, whichever report arrived first.
685
+ */
686
+ let displayName = undefined;
687
+ let platform = undefined;
688
+ for (const resolved of groupClaims) {
689
+ if (!displayName && resolved.claim.hasAdvertisedName) {
690
+ displayName = resolved.claim.displayName;
691
+ }
692
+ if (!platform && resolved.claim.remotePlatform) {
693
+ platform = resolved.claim.remotePlatform;
694
+ }
695
+ }
696
+ if (!displayName) {
697
+ for (const resolved of groupClaims) {
698
+ if (resolved.claim.displayName) {
699
+ displayName = resolved.claim.displayName;
700
+ break;
701
+ }
702
+ }
703
+ }
704
+ /*
705
+ * The id keeps its historic `unmanaged:<value>` shape — it is the key
706
+ * saved arrangements are stored under, so changing it would scatter
707
+ * every pinned peer on the map. It is named after the label wherever
708
+ * that label is one of the peer's own aliases, so merging a report
709
+ * that knew a sysName with one that knew only a chassis MAC still
710
+ * produces `unmanaged:ap-lobby` rather than an id made of hex.
711
+ */
712
+ const nodeId = NetworkTopologyUtil.uniqueNodeId(`unmanaged:${NetworkTopologyUtil.canonicalPeerValue(groupClaims, displayName)}`, usedNodeIds);
713
+ usedNodeIds.add(nodeId);
714
+ const unmanagedName = displayName || "Unknown device";
715
+ nodes.push({
716
+ id: nodeId,
717
+ name: unmanagedName,
718
+ isManaged: false,
719
+ kind: "unmanaged",
720
+ /*
721
+ * Classified from the whole group rather than from whichever
722
+ * report happened to be first: the platform string is usually the
723
+ * only real evidence about a peer, and it may well arrive on the
724
+ * second report of it.
725
+ */
726
+ role: classifyDeviceRole({
727
+ platform: platform,
728
+ name: unmanagedName,
729
+ }),
730
+ status: "unknown",
731
+ deviceModel: platform,
732
+ });
733
+ for (const resolved of groupClaims) {
734
+ nodeIdByClaim.set(resolved, nodeId);
735
+ }
736
+ }
737
+ return nodeIdByClaim;
738
+ }
739
+ /*
740
+ * The alias a merged peer is named after.
741
+ *
742
+ * The chosen label wins whenever it is genuinely one of the peer's own
743
+ * aliases; otherwise the strongest kind present decides, and within it
744
+ * the lexicographically smallest value, so the id never depends on which
745
+ * switch happened to be polled first.
746
+ */
747
+ static canonicalPeerValue(groupClaims, displayName) {
748
+ const valuesByKind = new Map();
749
+ for (const resolved of groupClaims) {
750
+ for (const alias of resolved.peerAliases) {
751
+ const bucket = valuesByKind.get(alias.kind);
752
+ if (bucket) {
753
+ if (!bucket.includes(alias.value)) {
754
+ bucket.push(alias.value);
755
+ }
756
+ }
757
+ else {
758
+ valuesByKind.set(alias.kind, [alias.value]);
759
+ }
760
+ }
761
+ }
762
+ const preferred = NetworkTopologyUtil.normalizeKey(displayName);
763
+ if (preferred && (valuesByKind.get("name") || []).includes(preferred)) {
764
+ return preferred;
765
+ }
766
+ for (const kind of MATCH_KEY_KINDS_STRONGEST_FIRST) {
767
+ const values = valuesByKind.get(kind);
768
+ if (values && values.length > 0) {
769
+ return [...values].sort()[0];
770
+ }
771
+ }
772
+ return "unknown-peer";
773
+ }
774
+ /*
775
+ * Two peers could in principle canonicalize to the same string (one by
776
+ * name, one by serial). Suffixing rather than merging keeps them the
777
+ * distinct boxes they are.
778
+ */
779
+ static uniqueNodeId(preferred, used) {
780
+ if (!used.has(preferred)) {
781
+ return preferred;
782
+ }
783
+ let suffix = 2;
784
+ while (used.has(`${preferred}#${suffix}`)) {
785
+ suffix++;
786
+ }
787
+ return `${preferred}#${suffix}`;
788
+ }
789
+ /*
790
+ * Union-find over peer aliases: two reports that share ANY identity-grade
791
+ * alias describe one box. Returns the representative alias id for every
792
+ * alias seen.
793
+ */
794
+ static groupPeerAliases(unmanagedClaims) {
795
+ const parent = new Map();
796
+ const find = (key) => {
797
+ let root = key;
798
+ let next = parent.get(root);
799
+ while (next !== undefined && next !== root) {
800
+ root = next;
801
+ next = parent.get(root);
802
+ }
803
+ // Path compression, so repeated lookups stay flat.
804
+ let cursor = key;
805
+ while (cursor !== root) {
806
+ const following = parent.get(cursor) || root;
807
+ parent.set(cursor, root);
808
+ cursor = following;
809
+ }
810
+ return root;
811
+ };
812
+ const union = (a, b) => {
813
+ const rootA = find(a);
814
+ const rootB = find(b);
815
+ if (rootA === rootB) {
816
+ return;
817
+ }
818
+ // Lexicographic tie-break, so the result ignores input order.
819
+ if (rootA < rootB) {
820
+ parent.set(rootB, rootA);
821
+ }
822
+ else {
823
+ parent.set(rootA, rootB);
824
+ }
825
+ };
826
+ for (const resolved of unmanagedClaims) {
827
+ const aliasIds = resolved.peerAliases.map((alias) => {
828
+ return NetworkTopologyUtil.matchKeyId(alias);
829
+ });
830
+ for (const aliasId of aliasIds) {
831
+ if (!parent.has(aliasId)) {
832
+ parent.set(aliasId, aliasId);
833
+ }
834
+ }
835
+ for (let index = 1; index < aliasIds.length; index++) {
836
+ union(aliasIds[0], aliasIds[index]);
837
+ }
838
+ }
839
+ const rootByAliasId = new Map();
840
+ for (const aliasId of parent.keys()) {
841
+ rootByAliasId.set(aliasId, find(aliasId));
842
+ }
843
+ return rootByAliasId;
844
+ }
348
845
  static normalizeKey(value) {
349
846
  if (!value) {
350
847
  return undefined;
@@ -352,7 +849,16 @@ export default class NetworkTopologyUtil {
352
849
  const trimmed = value.trim().toLowerCase();
353
850
  return trimmed.length > 0 ? trimmed : undefined;
354
851
  }
852
+ /*
853
+ * A stamped monitor status beats SNMP freshness, and freshness is the
854
+ * fallback — the same precedence SiteStatusRollupUtil already applies when
855
+ * it rolls devices up into a site, so a device cannot read "up" on the map
856
+ * and "down" on the site card above it.
857
+ */
355
858
  static deviceStatus(device, now) {
859
+ if (device.monitorStatus) {
860
+ return device.monitorStatus;
861
+ }
356
862
  return NetworkTopologyUtil.statusFromLastSeen(device.lastSeenAt, now);
357
863
  }
358
864
  // The shared freshness rule: seen within the window = up, stale = down.