@oneuptime/common 12.0.7 → 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 (873) 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} +184 -9
  9. package/Models/DatabaseModels/InventoryItemCustomField.ts +434 -0
  10. package/Models/DatabaseModels/{TelemetryEntityRelationship.ts → InventoryItemRelationship.ts} +33 -7
  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/WorkflowLog.ts +38 -0
  27. package/Models/DatabaseModels/WorkflowVariable.ts +12 -0
  28. package/Server/API/AIChatAPI.ts +315 -1
  29. package/Server/API/DashboardAPI.ts +217 -1
  30. package/Server/API/OnCallReadinessAPI.ts +841 -0
  31. package/Server/API/TeamComplianceAPI.ts +69 -17
  32. package/Server/API/TelemetryAPI.ts +220 -12
  33. package/Server/API/UserAPI.ts +16 -1
  34. package/Server/EnvironmentConfig.ts +52 -0
  35. package/Server/Infrastructure/Postgres/DataSourceOptions.ts +22 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +4 -4
  37. package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +5 -5
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/1786551733814-MigrationName.ts +41 -0
  39. package/Server/Infrastructure/Postgres/SchemaMigrations/1786559879134-AddWorkflowLogStepTrace.ts +17 -0
  40. package/Server/Infrastructure/Postgres/SchemaMigrations/1786625176831-AddMonitoringMethodToNetworkDevice.ts +35 -0
  41. package/Server/Infrastructure/Postgres/SchemaMigrations/1786634985763-AddNetworkDeviceLink.ts +82 -0
  42. package/Server/Infrastructure/Postgres/SchemaMigrations/1786639512056-AddNetworkDeviceLinkRule.ts +91 -0
  43. package/Server/Infrastructure/Postgres/SchemaMigrations/1786639972982-AddNetworkTopologySuppression.ts +47 -0
  44. package/Server/Infrastructure/Postgres/SchemaMigrations/1786800000000-RenameTelemetryEntityToInventoryItem.ts +255 -0
  45. package/Server/Infrastructure/Postgres/SchemaMigrations/1786900000000-AddInventoryItemArchiveAndCustomFields.ts +107 -0
  46. package/Server/Infrastructure/Postgres/SchemaMigrations/1787000000000-AddOnCallNotificationFallbackColumns.ts +90 -0
  47. package/Server/Infrastructure/Postgres/SchemaMigrations/1787100000000-AddAIConversationPageContext.ts +39 -0
  48. package/Server/Infrastructure/Postgres/SchemaMigrations/1787200000000-AddAIChatMessageFeedback.ts +33 -0
  49. package/Server/Infrastructure/Postgres/SchemaMigrations/1787300000000-AddEpisodeMemberNotifyIndexes.ts +59 -0
  50. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +24 -0
  51. package/Server/Infrastructure/Queue.ts +78 -13
  52. package/Server/Middleware/MasterAdminAuthorization.ts +11 -6
  53. package/Server/Middleware/PublicDashboardRateLimit.ts +593 -0
  54. package/Server/Services/AIService.ts +7 -0
  55. package/Server/Services/AlertEpisodeStateTimelineService.ts +29 -0
  56. package/Server/Services/AlertSeverityService.ts +63 -0
  57. package/Server/Services/DashboardService.ts +9 -10
  58. package/Server/Services/DatabaseService.ts +32 -2
  59. package/Server/Services/IncidentEpisodeStateTimelineService.ts +29 -0
  60. package/Server/Services/IncidentSeverityService.ts +76 -0
  61. package/Server/Services/Index.ts +12 -4
  62. package/Server/Services/InventoryItemCustomFieldService.ts +9 -0
  63. package/Server/Services/{TelemetryEntityRelationshipService.ts → InventoryItemRelationshipService.ts} +7 -4
  64. package/Server/Services/{TelemetryEntityService.ts → InventoryItemService.ts} +203 -21
  65. package/Server/Services/LogAggregationService.ts +45 -8
  66. package/Server/Services/MetricAggregationService.ts +121 -0
  67. package/Server/Services/MetricService.ts +7 -7
  68. package/Server/Services/NetworkDeviceLinkRuleService.ts +10 -0
  69. package/Server/Services/NetworkDeviceLinkService.ts +84 -0
  70. package/Server/Services/NetworkDeviceService.ts +140 -0
  71. package/Server/Services/NetworkSiteService.ts +77 -25
  72. package/Server/Services/NetworkTopologySuppressionService.ts +84 -0
  73. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +41 -29
  74. package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +8 -0
  75. package/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.ts +62 -13
  76. package/Server/Services/OnCallDutyPolicyScheduleService.ts +61 -1
  77. package/Server/Services/OnCallNotificationAlertingService.ts +742 -0
  78. package/Server/Services/OnCallReadinessService.ts +2803 -0
  79. package/Server/Services/OnCallSetupReminderService.ts +955 -0
  80. package/Server/Services/ProfileAggregationService.ts +123 -0
  81. package/Server/Services/StatusPageService.ts +9 -10
  82. package/Server/Services/TeamComplianceService.ts +429 -252
  83. package/Server/Services/UserCallService.ts +26 -1
  84. package/Server/Services/UserEmailService.ts +26 -1
  85. package/Server/Services/UserNotificationRuleAdminService.ts +1183 -0
  86. package/Server/Services/UserNotificationRuleService.ts +3812 -333
  87. package/Server/Services/UserOnCallLogService.ts +561 -48
  88. package/Server/Services/UserPushService.ts +29 -0
  89. package/Server/Services/UserService.ts +11 -0
  90. package/Server/Services/UserSmsService.ts +26 -1
  91. package/Server/Services/UserTelegramService.ts +24 -1
  92. package/Server/Services/UserWebhookService.ts +28 -1
  93. package/Server/Services/UserWhatsAppService.ts +24 -1
  94. package/Server/Types/Database/Permissions/BasePermission.ts +19 -0
  95. package/Server/Types/Database/Permissions/CreatePermission.ts +164 -0
  96. package/Server/Types/Database/Permissions/OwnerOnlyColumnPermission.ts +340 -0
  97. package/Server/Types/Database/Permissions/QueryPermission.ts +48 -0
  98. package/Server/Types/Database/Permissions/TenantPermission.ts +8 -1
  99. package/Server/Types/Workflow/Components/API/Delete.ts +1 -1
  100. package/Server/Types/Workflow/Components/API/Get.ts +1 -1
  101. package/Server/Types/Workflow/Components/API/Patch.ts +1 -1
  102. package/Server/Types/Workflow/Components/API/Post.ts +1 -1
  103. package/Server/Types/Workflow/Components/API/Put.ts +1 -1
  104. package/Server/Types/Workflow/Components/API/Utils.ts +44 -1
  105. package/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.ts +29 -5
  106. package/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.ts +18 -10
  107. package/Server/Types/Workflow/Components/BaseModel/ModelArguments.ts +55 -0
  108. package/Server/Types/Workflow/Components/Conditions/IfElse.ts +3 -17
  109. package/Server/Types/Workflow/Components/Email.ts +25 -7
  110. package/Server/Types/Workflow/Components/JavaScript.ts +10 -3
  111. package/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.ts +1 -1
  112. package/Server/Types/Workflow/TriggerCode.ts +12 -0
  113. package/Server/Types/Workflow/Workflow.ts +5 -0
  114. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +643 -48
  115. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +32 -3
  116. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +20 -6
  117. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +7 -0
  118. package/Server/Utils/AI/Toolbox/AIActionTools.ts +2 -2
  119. package/Server/Utils/AI/Toolbox/AIMetaTools.ts +863 -0
  120. package/Server/Utils/AI/Toolbox/AlertTools.ts +177 -15
  121. package/Server/Utils/AI/Toolbox/IncidentTools.ts +191 -10
  122. package/Server/Utils/AI/Toolbox/Index.ts +48 -0
  123. package/Server/Utils/AI/Toolbox/MonitorTools.ts +298 -11
  124. package/Server/Utils/AI/Toolbox/NoteWriteTools.ts +295 -0
  125. package/Server/Utils/AI/Toolbox/OnCallTools.ts +1246 -0
  126. package/Server/Utils/AI/Toolbox/RunbookTools.ts +424 -0
  127. package/Server/Utils/AI/Toolbox/SloTools.ts +456 -0
  128. package/Server/Utils/AI/Toolbox/StatusPageTools.ts +559 -0
  129. package/Server/Utils/AI/Toolbox/TeamTools.ts +327 -0
  130. package/Server/Utils/AI/Toolbox/TimelineTools.ts +615 -0
  131. package/Server/Utils/AI/Toolbox/WorkflowProbeTools.ts +664 -0
  132. package/Server/Utils/ClientIp.ts +221 -0
  133. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +47 -0
  134. package/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.ts +163 -0
  135. package/Server/Utils/Dashboard/PublicDashboardSloWidget.ts +147 -0
  136. package/Server/Utils/Express.ts +12 -17
  137. package/Server/Utils/LLM/LLMService.ts +85 -8
  138. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +204 -10
  139. package/Server/Utils/SSRFProtection.ts +98 -23
  140. package/Server/Utils/StartServer.ts +12 -3
  141. package/Server/Utils/Telemetry/EntityRegistry.ts +205 -18
  142. package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +689 -0
  143. package/Server/Utils/Telemetry/TelemetryEntity.ts +160 -52
  144. package/Server/Utils/VM/VMAPI.ts +56 -8
  145. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +7 -3
  146. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +2146 -0
  147. package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +561 -0
  148. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +2470 -0
  149. package/Tests/App/Dashboard/MonitorCriteriaAttributeFilter.test.tsx +574 -0
  150. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +1897 -0
  151. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3606 -0
  152. package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +784 -0
  153. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +1119 -0
  154. package/Tests/App/Dashboard/SloWidgetFetching.test.tsx +531 -0
  155. package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +1312 -0
  156. package/Tests/App/Dashboard/UserSettingsSetupChecklistPage.test.tsx +1390 -0
  157. package/Tests/Models/InventoryItemModel.test.ts +174 -0
  158. package/Tests/Models/InventoryItemNaming.test.ts +302 -0
  159. package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +437 -0
  160. package/Tests/Server/API/DashboardPublicRateLimit.test.ts +659 -0
  161. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +18 -0
  162. package/Tests/Server/API/DashboardPublicSloAPI.test.ts +880 -0
  163. package/Tests/Server/API/Helpers.ts +24 -15
  164. package/Tests/Server/API/OnCallReadinessAPI.test.ts +2680 -0
  165. package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +915 -0
  166. package/Tests/Server/API/UserProjectsAPI.test.ts +478 -4
  167. package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +533 -0
  168. package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +213 -0
  169. package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +432 -0
  170. package/Tests/Server/Infrastructure/Queue.test.ts +293 -0
  171. package/Tests/Server/Middleware/PublicDashboardRateLimit.test.ts +1645 -0
  172. package/Tests/Server/Services/AdminRuleEditGuards.test.ts +2848 -0
  173. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1393 -0
  174. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +1802 -0
  175. package/Tests/Server/Services/EpisodeStateTimelineNote.test.ts +304 -0
  176. package/Tests/Server/Services/InventoryItemDisplayName.test.ts +339 -0
  177. package/Tests/Server/Services/InventoryItemManualCreate.test.ts +248 -0
  178. package/Tests/Server/Services/IpAllowlistSpoofing.test.ts +450 -0
  179. package/Tests/Server/Services/LogAggregationService.test.ts +235 -1
  180. package/Tests/Server/Services/MetricAggregationService.test.ts +231 -0
  181. package/Tests/Server/Services/MetricEntityMVKeyParity.test.ts +80 -29
  182. package/Tests/Server/Services/MetricServiceAggregate.test.ts +30 -30
  183. package/Tests/Server/Services/NetworkSiteService.test.ts +18 -3
  184. package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +1728 -0
  185. package/Tests/Server/Services/NotificationDeletionImpact.test.ts +2402 -0
  186. package/Tests/Server/Services/OnCallDutyPolicyExecutionLogTimelineGapFeed.test.ts +394 -0
  187. package/Tests/Server/Services/OnCallNotificationFallback.test.ts +1744 -0
  188. package/Tests/Server/Services/OnCallReadinessService.test.ts +4295 -0
  189. package/Tests/Server/Services/OnCallSetupReminder.test.ts +1272 -0
  190. package/Tests/Server/Services/OnCallWeeklyReadinessDigest.test.ts +1021 -0
  191. package/Tests/Server/Services/ProfileAggregationService.test.ts +296 -0
  192. package/Tests/Server/Services/SeverityCreationRuleBackfill.test.ts +1536 -0
  193. package/Tests/Server/Services/SeverityRuleBackfill.test.ts +1818 -0
  194. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +1845 -0
  195. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +1394 -0
  196. package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +1166 -0
  197. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1468 -0
  198. package/Tests/Server/Services/UserOnCallLogNoNotificationRules.test.ts +1457 -0
  199. package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +1546 -0
  200. package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +529 -0
  201. package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +1219 -0
  202. package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +1089 -0
  203. package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +2 -1
  204. package/Tests/Server/Types/Workflow/Components/ApiComponentHeaders.test.ts +192 -0
  205. package/Tests/Server/Types/Workflow/Components/BaseModelDatabaseComponents.test.ts +190 -0
  206. package/Tests/Server/Types/Workflow/Components/ChatWebhookComponents.test.ts +44 -14
  207. package/Tests/Server/Types/Workflow/Components/Email.test.ts +151 -0
  208. package/Tests/Server/Types/Workflow/Components/IfElse.test.ts +98 -0
  209. package/Tests/Server/Types/Workflow/Components/JavaScript.test.ts +51 -0
  210. package/Tests/Server/Utils/AI/AIMetaTools.test.ts +586 -0
  211. package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +582 -0
  212. package/Tests/Server/Utils/AI/ChatAgentRunner.test.ts +726 -0
  213. package/Tests/Server/Utils/AI/IncidentToolsFilters.test.ts +315 -0
  214. package/Tests/Server/Utils/AI/LLMServiceStopReason.test.ts +314 -0
  215. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +26 -3
  216. package/Tests/Server/Utils/AI/NoteWriteTools.test.ts +268 -0
  217. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +169 -0
  218. package/Tests/Server/Utils/AI/OnCallTools.test.ts +664 -0
  219. package/Tests/Server/Utils/AI/RunbookTools.test.ts +325 -0
  220. package/Tests/Server/Utils/AI/SloTools.test.ts +306 -0
  221. package/Tests/Server/Utils/AI/StatusPageTools.test.ts +391 -0
  222. package/Tests/Server/Utils/AI/TeamTools.test.ts +257 -0
  223. package/Tests/Server/Utils/AI/TimelineTools.test.ts +472 -0
  224. package/Tests/Server/Utils/AI/WorkflowProbeTools.test.ts +428 -0
  225. package/Tests/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.test.ts +152 -0
  226. package/Tests/Server/Utils/ClientIp.test.ts +438 -0
  227. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +171 -0
  228. package/Tests/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.test.ts +383 -0
  229. package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +23 -25
  230. package/Tests/Server/Utils/MicrosoftTeamsWebhookUrlValidation.test.ts +6 -0
  231. package/Tests/Server/Utils/Monitor/Criteria/DnssecMonitorCriteria.test.ts +307 -0
  232. package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +468 -0
  233. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorTelemetryDeepLinks.test.ts +460 -0
  234. package/Tests/Server/Utils/ResponseRateLimitStatusCodes.test.ts +137 -0
  235. package/Tests/Server/Utils/SSRFProtectionBypasses.test.ts +40 -8
  236. package/Tests/Server/Utils/SSRFProtectionUserInfo.test.ts +351 -0
  237. package/Tests/Server/Utils/Telemetry/EntityRegistryRetirement.test.ts +531 -0
  238. package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +322 -0
  239. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +356 -39
  240. package/Tests/Server/Utils/VM/VMAPISubstitution.test.ts +243 -0
  241. package/Tests/Types/IP/IP.test.ts +263 -0
  242. package/Tests/Types/IP/IPWhitelist.test.ts +197 -0
  243. package/Tests/Types/IP/IPv6.test.ts +12 -1
  244. package/Tests/Types/Monitor/SnmpOid.test.ts +64 -0
  245. package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +110 -0
  246. package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeAudit.test.ts +106 -0
  247. package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeDifferential.test.ts +511 -0
  248. package/Tests/Types/OnCallDutyPolicy/ScheduleCoverageEndToEnd.test.ts +489 -0
  249. package/Tests/Types/OnCallDutyPolicy/ScheduleCoverageGapTolerance.test.ts +479 -0
  250. package/Tests/Types/OnCallDutyPolicy/ScheduleCoverageState.test.ts +822 -0
  251. package/Tests/Types/SerializableObjectDictionaryImportCycle.test.ts +197 -0
  252. package/Tests/Types/Telemetry/EntityTypeGroups.test.ts +140 -0
  253. package/Tests/Types/Workflow/BaseModelComponents.test.ts +429 -0
  254. package/Tests/Types/Workflow/Components/BaseModel.test.ts +225 -0
  255. package/Tests/Types/Workflow/IntegrationCredentialMetadata.test.ts +100 -0
  256. package/Tests/Types/Workflow/StepTrace.test.ts +235 -0
  257. package/Tests/Types/Workflow/TemplateSyntax.test.ts +491 -0
  258. package/Tests/Types/Workflow/Templates.test.ts +1218 -0
  259. package/Tests/UI/Components/ActiveFilterChipsOpenRoute.test.tsx +82 -0
  260. package/Tests/UI/Components/ComponentsModal.test.tsx +564 -7
  261. package/Tests/UI/Components/CustomTimeRangeModal.test.tsx +459 -0
  262. package/Tests/UI/Components/DictionaryAttributeFilterRow.test.tsx +477 -0
  263. package/Tests/UI/Components/Forms/AnchoredFieldPopupKeyboard.test.tsx +382 -0
  264. package/Tests/UI/Components/Forms/ColorPickerPicking.test.tsx +569 -0
  265. package/Tests/UI/Components/Forms/ValidationJSON.test.ts +241 -0
  266. package/Tests/UI/Components/KeyboardShortcut.test.tsx +95 -0
  267. package/Tests/UI/Components/LogDetailsPanelCrossSignal.test.tsx +448 -0
  268. package/Tests/UI/Components/LogTimeRangePicker.test.tsx +42 -0
  269. package/Tests/UI/Components/LogsTableCrossLinks.test.tsx +263 -0
  270. package/Tests/UI/Components/ModalPortalDismissal.test.tsx +90 -0
  271. package/Tests/UI/Components/PendingProjectInvitations.test.tsx +913 -0
  272. package/Tests/UI/Components/SimpleLogViewer.test.tsx +228 -0
  273. package/Tests/UI/Components/TableRowSelectability.test.tsx +312 -0
  274. package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +49 -7
  275. package/Tests/UI/Components/TimeRangePickerDropdown.test.tsx +325 -0
  276. package/Tests/UI/Components/Workflow/GraphLint.test.ts +893 -0
  277. package/Tests/UI/Components/Workflow/GraphLintSummary.test.ts +755 -0
  278. package/Tests/UI/Components/Workflow/ModelColumnEditor.test.ts +522 -0
  279. package/Tests/UI/Components/Workflow/ModelColumnEditorServerContract.test.ts +193 -0
  280. package/Tests/UI/Components/Workflow/ModelSchema.test.ts +388 -0
  281. package/Tests/UI/Components/Workflow/RunStatusWatcher.test.ts +210 -0
  282. package/Tests/UI/Components/Workflow/StepTraceViewer.test.tsx +256 -0
  283. package/Tests/UI/Components/Workflow/UseRunWatch.test.tsx +665 -0
  284. package/Tests/UI/Components/Workflow/Utils.test.ts +192 -0
  285. package/Tests/UI/Components/Workflow/WorkflowIssuesModal.test.tsx +485 -0
  286. package/Tests/UI/Components/Workflow/WorkflowLogModal.test.tsx +478 -0
  287. package/Tests/UI/Components/Workflow/WorkflowStatusBar.test.tsx +379 -0
  288. package/Tests/UI/EsbuildConfig.test.ts +607 -0
  289. package/Tests/UI/Monitor/MonitorStepCriteriaView.test.tsx +432 -0
  290. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +5 -0
  291. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +11 -4
  292. package/Tests/UI/Utils/ModelAPICreateMiscData.test.ts +94 -0
  293. package/Tests/UI/Utils/Platform.test.ts +147 -0
  294. package/Tests/UI/Utils/ProjectInvitationDisplay.test.ts +357 -0
  295. package/Tests/Utils/Monitor/NetworkDeviceLinkRuleUtil.test.ts +198 -0
  296. package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +514 -0
  297. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +727 -0
  298. package/Tests/Utils/Schema/AnalyticsModelSchema.test.ts +469 -0
  299. package/Tests/Utils/Schema/ModelSchema.test.ts +268 -0
  300. package/Tests/Utils/Telemetry/CrossSignalScope.test.ts +698 -0
  301. package/Tests/Utils/Telemetry/EntityKeyNonTelemetry.test.ts +193 -0
  302. package/Tests/__mocks__/bullmq.js +55 -0
  303. package/Types/AI/AIChatMessageStatus.ts +8 -1
  304. package/Types/AI/AIChatTypes.ts +12 -0
  305. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +88 -0
  306. package/Types/Exception/ExceptionCode.ts +2 -0
  307. package/Types/Exception/ServiceUnavailableException.ts +8 -0
  308. package/Types/Exception/TooManyRequestsException.ts +8 -0
  309. package/Types/IP/IP.ts +93 -47
  310. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +80 -3
  311. package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +55 -0
  312. package/Types/OnCallDutyPolicy/Layer.ts +203 -149
  313. package/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.ts +13 -0
  314. package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +155 -10
  315. package/Types/Permission.ts +193 -0
  316. package/Types/SerializableObjectDictionary.ts +133 -39
  317. package/Types/Telemetry/EntityRelationshipType.ts +1 -1
  318. package/Types/Telemetry/EntitySource.ts +40 -0
  319. package/Types/Telemetry/EntityType.ts +28 -1
  320. package/Types/Telemetry/EntityTypeGroups.ts +65 -0
  321. package/Types/Workflow/Component.ts +29 -0
  322. package/Types/Workflow/Components/API.ts +35 -0
  323. package/Types/Workflow/Components/BaseModel.ts +77 -27
  324. package/Types/Workflow/Components/Discord.ts +1 -0
  325. package/Types/Workflow/Components/Email.ts +12 -3
  326. package/Types/Workflow/Components/JavaScript.ts +7 -0
  327. package/Types/Workflow/Components/MicrosoftTeams.ts +3 -2
  328. package/Types/Workflow/Components/Slack.ts +1 -0
  329. package/Types/Workflow/Components/Telegram.ts +1 -0
  330. package/Types/Workflow/StepTrace.ts +181 -0
  331. package/Types/Workflow/TemplateSyntax.ts +543 -0
  332. package/Types/Workflow/Templates.ts +2368 -0
  333. package/UI/Components/Calendar/Calendar.css +43 -0
  334. package/UI/Components/Calendar/Calendar.tsx +8 -0
  335. package/UI/Components/Card/Card.tsx +2 -2
  336. package/UI/Components/Checkbox/Checkbox.tsx +16 -0
  337. package/UI/Components/Date/CustomTimeRangeModal.tsx +278 -0
  338. package/UI/Components/Date/TimeRangePickerDropdown.tsx +250 -0
  339. package/UI/Components/Dictionary/Dictionary.tsx +71 -15
  340. package/UI/Components/FormModal/BasicFormModal.tsx +2 -1
  341. package/UI/Components/Forms/Fields/ColorPicker.tsx +66 -10
  342. package/UI/Components/Forms/Fields/IconPicker.tsx +48 -10
  343. package/UI/Components/Forms/Types/Field.ts +7 -0
  344. package/UI/Components/Forms/Validation.ts +63 -1
  345. package/UI/Components/Header/HeaderIconDropdownButton.tsx +53 -3
  346. package/UI/Components/Input/Input.tsx +32 -3
  347. package/UI/Components/KeyboardShortcut/KeyboardKey.ts +185 -0
  348. package/UI/Components/KeyboardShortcut/KeyboardShortcut.tsx +87 -0
  349. package/UI/Components/LogsViewer/LogsViewer.tsx +28 -0
  350. package/UI/Components/LogsViewer/components/ActiveFilterChips.tsx +31 -0
  351. package/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.tsx +18 -18
  352. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +363 -14
  353. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +11 -216
  354. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +11 -0
  355. package/UI/Components/LogsViewer/components/LogsTable.tsx +155 -12
  356. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +29 -0
  357. package/UI/Components/LogsViewer/types.ts +23 -0
  358. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +9 -2
  359. package/UI/Components/Modal/Modal.tsx +37 -4
  360. package/UI/Components/Navbar/NavBarMenuModal.tsx +15 -30
  361. package/UI/Components/ProjectInvitations/PendingProjectInvitations.tsx +442 -0
  362. package/UI/Components/SimpleLogViewer/SimpleLogViewer.tsx +23 -1
  363. package/UI/Components/Table/Table.tsx +49 -16
  364. package/UI/Components/Table/TableBody.tsx +53 -28
  365. package/UI/Components/Table/TableHeader.tsx +13 -0
  366. package/UI/Components/Table/TableRow.tsx +58 -26
  367. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +11 -210
  368. package/UI/Components/Workflow/ArgumentsForm.tsx +341 -8
  369. package/UI/Components/Workflow/Component.tsx +28 -26
  370. package/UI/Components/Workflow/ComponentReturnValueViewer.tsx +26 -0
  371. package/UI/Components/Workflow/ComponentSettingsModal.tsx +79 -9
  372. package/UI/Components/Workflow/ComponentValuePickerModal.tsx +135 -7
  373. package/UI/Components/Workflow/ComponentsModal.tsx +116 -22
  374. package/UI/Components/Workflow/DocumentationViewer.tsx +59 -9
  375. package/UI/Components/Workflow/GraphLint.ts +628 -0
  376. package/UI/Components/Workflow/GraphLintSummary.ts +390 -0
  377. package/UI/Components/Workflow/ModelColumnEditor.tsx +528 -0
  378. package/UI/Components/Workflow/ModelSchema.ts +278 -0
  379. package/UI/Components/Workflow/RunForm.tsx +41 -7
  380. package/UI/Components/Workflow/RunStatusWatcher.ts +122 -0
  381. package/UI/Components/Workflow/StepTraceViewer.tsx +186 -0
  382. package/UI/Components/Workflow/UseRunWatch.ts +212 -0
  383. package/UI/Components/Workflow/Utils.ts +93 -1
  384. package/UI/Components/Workflow/VariableModal.tsx +6 -2
  385. package/UI/Components/Workflow/Workflow.tsx +126 -7
  386. package/UI/Components/Workflow/WorkflowIssuesModal.tsx +255 -0
  387. package/UI/Components/Workflow/WorkflowLogModal.tsx +128 -0
  388. package/UI/Components/Workflow/WorkflowStatusBar.tsx +224 -0
  389. package/UI/Types/LayeredDismissal.ts +31 -0
  390. package/UI/Types/UseAnchoredFieldPopup.ts +99 -0
  391. package/UI/Utils/AIChatExport/ConversationMarkdown.ts +10 -0
  392. package/UI/Utils/ModelAPI/ModelAPI.ts +7 -1
  393. package/UI/Utils/Platform.ts +149 -0
  394. package/UI/Utils/ProjectInvitationDisplay.ts +118 -0
  395. package/UI/esbuild-config.js +22 -1
  396. package/Utils/Monitor/NetworkDeviceLinkRuleUtil.ts +187 -0
  397. package/Utils/Monitor/NetworkDeviceRoleUtil.ts +533 -0
  398. package/Utils/Monitor/NetworkTopologyUtil.ts +917 -155
  399. package/Utils/Telemetry/CrossSignalScope.ts +502 -0
  400. package/Utils/Telemetry/EntityKey.ts +71 -5
  401. package/Utils/Telemetry/EntityRelationship.ts +1 -1
  402. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByK8sCluster.js +1 -1
  403. package/build/dist/Models/AnalyticsModels/MetricItemAggMV1mByService.js +1 -1
  404. package/build/dist/Models/DatabaseModels/AIConversation.js +32 -0
  405. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
  406. package/build/dist/Models/DatabaseModels/AIConversationMessage.js +42 -0
  407. package/build/dist/Models/DatabaseModels/AIConversationMessage.js.map +1 -1
  408. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +28 -0
  409. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -1
  410. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +29 -0
  411. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -1
  412. package/build/dist/Models/DatabaseModels/Index.js +12 -4
  413. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  414. package/build/dist/Models/DatabaseModels/{TelemetryEntity.js → InventoryItem.js} +212 -29
  415. package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -0
  416. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js +454 -0
  417. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js.map +1 -0
  418. package/build/dist/Models/DatabaseModels/{TelemetryEntityRelationship.js → InventoryItemRelationship.js} +52 -25
  419. package/build/dist/Models/DatabaseModels/InventoryItemRelationship.js.map +1 -0
  420. package/build/dist/Models/DatabaseModels/NetworkDevice.js +141 -0
  421. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  422. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +719 -0
  423. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -0
  424. package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js +475 -0
  425. package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js.map +1 -0
  426. package/build/dist/Models/DatabaseModels/NetworkTopologySuppression.js +446 -0
  427. package/build/dist/Models/DatabaseModels/NetworkTopologySuppression.js.map +1 -0
  428. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyFeed.js +9 -0
  429. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyFeed.js.map +1 -1
  430. package/build/dist/Models/DatabaseModels/Project.js +80 -0
  431. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  432. package/build/dist/Models/DatabaseModels/UserCall.js +46 -2
  433. package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
  434. package/build/dist/Models/DatabaseModels/UserEmail.js +48 -2
  435. package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
  436. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +424 -55
  437. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  438. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +24 -2
  439. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  440. package/build/dist/Models/DatabaseModels/UserPush.js +51 -1
  441. package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
  442. package/build/dist/Models/DatabaseModels/UserSMS.js +47 -2
  443. package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
  444. package/build/dist/Models/DatabaseModels/UserTelegram.js +65 -3
  445. package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
  446. package/build/dist/Models/DatabaseModels/UserWebhook.js +56 -2
  447. package/build/dist/Models/DatabaseModels/UserWebhook.js.map +1 -1
  448. package/build/dist/Models/DatabaseModels/UserWhatsApp.js +45 -2
  449. package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
  450. package/build/dist/Models/DatabaseModels/WorkflowLog.js +39 -0
  451. package/build/dist/Models/DatabaseModels/WorkflowLog.js.map +1 -1
  452. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +12 -0
  453. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  454. package/build/dist/Server/API/AIChatAPI.js +237 -1
  455. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  456. package/build/dist/Server/API/DashboardAPI.js +165 -13
  457. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  458. package/build/dist/Server/API/OnCallReadinessAPI.js +599 -0
  459. package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -0
  460. package/build/dist/Server/API/TeamComplianceAPI.js +68 -9
  461. package/build/dist/Server/API/TeamComplianceAPI.js.map +1 -1
  462. package/build/dist/Server/API/TelemetryAPI.js +129 -18
  463. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  464. package/build/dist/Server/API/UserAPI.js +16 -1
  465. package/build/dist/Server/API/UserAPI.js.map +1 -1
  466. package/build/dist/Server/EnvironmentConfig.js +45 -0
  467. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  468. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +22 -0
  469. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
  470. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +4 -4
  471. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786551733814-MigrationName.js +20 -0
  472. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786551733814-MigrationName.js.map +1 -0
  473. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786559879134-AddWorkflowLogStepTrace.js +12 -0
  474. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786559879134-AddWorkflowLogStepTrace.js.map +1 -0
  475. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786625176831-AddMonitoringMethodToNetworkDevice.js +18 -0
  476. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786625176831-AddMonitoringMethodToNetworkDevice.js.map +1 -0
  477. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786634985763-AddNetworkDeviceLink.js +39 -0
  478. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786634985763-AddNetworkDeviceLink.js.map +1 -0
  479. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639512056-AddNetworkDeviceLinkRule.js +38 -0
  480. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639512056-AddNetworkDeviceLinkRule.js.map +1 -0
  481. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639972982-AddNetworkTopologySuppression.js +22 -0
  482. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786639972982-AddNetworkTopologySuppression.js.map +1 -0
  483. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786800000000-RenameTelemetryEntityToInventoryItem.js +150 -0
  484. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786800000000-RenameTelemetryEntityToInventoryItem.js.map +1 -0
  485. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786900000000-AddInventoryItemArchiveAndCustomFields.js +57 -0
  486. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786900000000-AddInventoryItemArchiveAndCustomFields.js.map +1 -0
  487. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787000000000-AddOnCallNotificationFallbackColumns.js +69 -0
  488. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787000000000-AddOnCallNotificationFallbackColumns.js.map +1 -0
  489. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787100000000-AddAIConversationPageContext.js +32 -0
  490. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787100000000-AddAIConversationPageContext.js.map +1 -0
  491. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787200000000-AddAIChatMessageFeedback.js +26 -0
  492. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787200000000-AddAIChatMessageFeedback.js.map +1 -0
  493. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787300000000-AddEpisodeMemberNotifyIndexes.js +48 -0
  494. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787300000000-AddEpisodeMemberNotifyIndexes.js.map +1 -0
  495. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +24 -0
  496. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  497. package/build/dist/Server/Infrastructure/Queue.js +72 -13
  498. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  499. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -6
  500. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  501. package/build/dist/Server/Middleware/PublicDashboardRateLimit.js +399 -0
  502. package/build/dist/Server/Middleware/PublicDashboardRateLimit.js.map +1 -0
  503. package/build/dist/Server/Services/AIService.js +1 -0
  504. package/build/dist/Server/Services/AIService.js.map +1 -1
  505. package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js +24 -3
  506. package/build/dist/Server/Services/AlertEpisodeStateTimelineService.js.map +1 -1
  507. package/build/dist/Server/Services/AlertSeverityService.js +54 -0
  508. package/build/dist/Server/Services/AlertSeverityService.js.map +1 -1
  509. package/build/dist/Server/Services/DashboardService.js +10 -9
  510. package/build/dist/Server/Services/DashboardService.js.map +1 -1
  511. package/build/dist/Server/Services/DatabaseService.js +24 -2
  512. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  513. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +24 -3
  514. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  515. package/build/dist/Server/Services/IncidentSeverityService.js +67 -0
  516. package/build/dist/Server/Services/IncidentSeverityService.js.map +1 -1
  517. package/build/dist/Server/Services/Index.js +12 -4
  518. package/build/dist/Server/Services/Index.js.map +1 -1
  519. package/build/dist/Server/Services/InventoryItemCustomFieldService.js +9 -0
  520. package/build/dist/Server/Services/InventoryItemCustomFieldService.js.map +1 -0
  521. package/build/dist/Server/Services/{TelemetryEntityRelationshipService.js → InventoryItemRelationshipService.js} +9 -6
  522. package/build/dist/Server/Services/InventoryItemRelationshipService.js.map +1 -0
  523. package/build/dist/Server/Services/{TelemetryEntityService.js → InventoryItemService.js} +158 -23
  524. package/build/dist/Server/Services/InventoryItemService.js.map +1 -0
  525. package/build/dist/Server/Services/LogAggregationService.js +27 -8
  526. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  527. package/build/dist/Server/Services/MetricAggregationService.js +80 -0
  528. package/build/dist/Server/Services/MetricAggregationService.js.map +1 -1
  529. package/build/dist/Server/Services/MetricService.js +6 -6
  530. package/build/dist/Server/Services/MetricService.js.map +1 -1
  531. package/build/dist/Server/Services/NetworkDeviceLinkRuleService.js +9 -0
  532. package/build/dist/Server/Services/NetworkDeviceLinkRuleService.js.map +1 -0
  533. package/build/dist/Server/Services/NetworkDeviceLinkService.js +71 -0
  534. package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -0
  535. package/build/dist/Server/Services/NetworkDeviceService.js +113 -0
  536. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  537. package/build/dist/Server/Services/NetworkSiteService.js +53 -13
  538. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  539. package/build/dist/Server/Services/NetworkTopologySuppressionService.js +85 -0
  540. package/build/dist/Server/Services/NetworkTopologySuppressionService.js.map +1 -0
  541. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +48 -32
  542. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  543. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +8 -0
  544. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
  545. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js +51 -12
  546. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogTimelineService.js.map +1 -1
  547. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +57 -13
  548. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  549. package/build/dist/Server/Services/OnCallNotificationAlertingService.js +548 -0
  550. package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -0
  551. package/build/dist/Server/Services/OnCallReadinessService.js +1961 -0
  552. package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -0
  553. package/build/dist/Server/Services/OnCallSetupReminderService.js +738 -0
  554. package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -0
  555. package/build/dist/Server/Services/ProfileAggregationService.js +68 -4
  556. package/build/dist/Server/Services/ProfileAggregationService.js.map +1 -1
  557. package/build/dist/Server/Services/StatusPageService.js +11 -10
  558. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  559. package/build/dist/Server/Services/TeamComplianceService.js +312 -160
  560. package/build/dist/Server/Services/TeamComplianceService.js.map +1 -1
  561. package/build/dist/Server/Services/UserCallService.js +24 -1
  562. package/build/dist/Server/Services/UserCallService.js.map +1 -1
  563. package/build/dist/Server/Services/UserEmailService.js +24 -1
  564. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  565. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +858 -0
  566. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -0
  567. package/build/dist/Server/Services/UserNotificationRuleService.js +2830 -175
  568. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  569. package/build/dist/Server/Services/UserOnCallLogService.js +488 -43
  570. package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
  571. package/build/dist/Server/Services/UserPushService.js +26 -0
  572. package/build/dist/Server/Services/UserPushService.js.map +1 -1
  573. package/build/dist/Server/Services/UserService.js +10 -0
  574. package/build/dist/Server/Services/UserService.js.map +1 -1
  575. package/build/dist/Server/Services/UserSmsService.js +24 -1
  576. package/build/dist/Server/Services/UserSmsService.js.map +1 -1
  577. package/build/dist/Server/Services/UserTelegramService.js +22 -1
  578. package/build/dist/Server/Services/UserTelegramService.js.map +1 -1
  579. package/build/dist/Server/Services/UserWebhookService.js +25 -1
  580. package/build/dist/Server/Services/UserWebhookService.js.map +1 -1
  581. package/build/dist/Server/Services/UserWhatsAppService.js +22 -1
  582. package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
  583. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +12 -1
  584. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  585. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +126 -0
  586. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  587. package/build/dist/Server/Types/Database/Permissions/OwnerOnlyColumnPermission.js +254 -0
  588. package/build/dist/Server/Types/Database/Permissions/OwnerOnlyColumnPermission.js.map +1 -0
  589. package/build/dist/Server/Types/Database/Permissions/QueryPermission.js +47 -2
  590. package/build/dist/Server/Types/Database/Permissions/QueryPermission.js.map +1 -1
  591. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +7 -0
  592. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
  593. package/build/dist/Server/Types/Workflow/Components/API/Delete.js +1 -1
  594. package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
  595. package/build/dist/Server/Types/Workflow/Components/API/Get.js +1 -1
  596. package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
  597. package/build/dist/Server/Types/Workflow/Components/API/Patch.js +1 -1
  598. package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
  599. package/build/dist/Server/Types/Workflow/Components/API/Post.js +1 -1
  600. package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
  601. package/build/dist/Server/Types/Workflow/Components/API/Put.js +1 -1
  602. package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
  603. package/build/dist/Server/Types/Workflow/Components/API/Utils.js +28 -0
  604. package/build/dist/Server/Types/Workflow/Components/API/Utils.js.map +1 -1
  605. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js +21 -5
  606. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js.map +1 -1
  607. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js +14 -10
  608. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js.map +1 -1
  609. package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js +31 -0
  610. package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js.map +1 -1
  611. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js +3 -9
  612. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js.map +1 -1
  613. package/build/dist/Server/Types/Workflow/Components/Email.js +15 -4
  614. package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
  615. package/build/dist/Server/Types/Workflow/Components/JavaScript.js +7 -2
  616. package/build/dist/Server/Types/Workflow/Components/JavaScript.js.map +1 -1
  617. package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js +1 -1
  618. package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js.map +1 -1
  619. package/build/dist/Server/Types/Workflow/TriggerCode.js.map +1 -1
  620. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +514 -56
  621. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  622. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +20 -3
  623. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  624. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +19 -6
  625. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  626. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +7 -0
  627. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  628. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js +2 -2
  629. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -1
  630. package/build/dist/Server/Utils/AI/Toolbox/AIMetaTools.js +692 -0
  631. package/build/dist/Server/Utils/AI/Toolbox/AIMetaTools.js.map +1 -0
  632. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +148 -12
  633. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
  634. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +157 -10
  635. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -1
  636. package/build/dist/Server/Utils/AI/Toolbox/Index.js +37 -0
  637. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  638. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js +259 -14
  639. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js.map +1 -1
  640. package/build/dist/Server/Utils/AI/Toolbox/NoteWriteTools.js +235 -0
  641. package/build/dist/Server/Utils/AI/Toolbox/NoteWriteTools.js.map +1 -0
  642. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +1000 -0
  643. package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -0
  644. package/build/dist/Server/Utils/AI/Toolbox/RunbookTools.js +356 -0
  645. package/build/dist/Server/Utils/AI/Toolbox/RunbookTools.js.map +1 -0
  646. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +394 -0
  647. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -0
  648. package/build/dist/Server/Utils/AI/Toolbox/StatusPageTools.js +465 -0
  649. package/build/dist/Server/Utils/AI/Toolbox/StatusPageTools.js.map +1 -0
  650. package/build/dist/Server/Utils/AI/Toolbox/TeamTools.js +280 -0
  651. package/build/dist/Server/Utils/AI/Toolbox/TeamTools.js.map +1 -0
  652. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js +527 -0
  653. package/build/dist/Server/Utils/AI/Toolbox/TimelineTools.js.map +1 -0
  654. package/build/dist/Server/Utils/AI/Toolbox/WorkflowProbeTools.js +548 -0
  655. package/build/dist/Server/Utils/AI/Toolbox/WorkflowProbeTools.js.map +1 -0
  656. package/build/dist/Server/Utils/ClientIp.js +137 -0
  657. package/build/dist/Server/Utils/ClientIp.js.map +1 -0
  658. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +38 -0
  659. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
  660. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js +89 -0
  661. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloHistoryPolicy.js.map +1 -0
  662. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js +77 -0
  663. package/build/dist/Server/Utils/Dashboard/PublicDashboardSloWidget.js.map +1 -0
  664. package/build/dist/Server/Utils/Express.js +12 -12
  665. package/build/dist/Server/Utils/Express.js.map +1 -1
  666. package/build/dist/Server/Utils/LLM/LLMService.js +70 -7
  667. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  668. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +121 -11
  669. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  670. package/build/dist/Server/Utils/SSRFProtection.js +82 -21
  671. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  672. package/build/dist/Server/Utils/StartServer.js +12 -4
  673. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  674. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +165 -18
  675. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  676. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +507 -0
  677. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -0
  678. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +122 -47
  679. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  680. package/build/dist/Server/Utils/VM/VMAPI.js +51 -4
  681. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  682. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +7 -3
  683. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  684. package/build/dist/Types/AI/AIChatMessageStatus.js +8 -1
  685. package/build/dist/Types/AI/AIChatMessageStatus.js.map +1 -1
  686. package/build/dist/Types/AI/AIChatTypes.js +12 -0
  687. package/build/dist/Types/AI/AIChatTypes.js.map +1 -1
  688. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +60 -0
  689. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -0
  690. package/build/dist/Types/Exception/ExceptionCode.js +2 -0
  691. package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
  692. package/build/dist/Types/Exception/ServiceUnavailableException.js +8 -0
  693. package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -0
  694. package/build/dist/Types/Exception/TooManyRequestsException.js +8 -0
  695. package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -0
  696. package/build/dist/Types/IP/IP.js +87 -43
  697. package/build/dist/Types/IP/IP.js.map +1 -1
  698. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +50 -0
  699. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -0
  700. package/build/dist/Types/OnCallDutyPolicy/Layer.js +186 -123
  701. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  702. package/build/dist/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.js +13 -0
  703. package/build/dist/Types/OnCallDutyPolicy/OnCallDutyPolicyStatus.js.map +1 -1
  704. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +105 -11
  705. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
  706. package/build/dist/Types/Permission.js +174 -0
  707. package/build/dist/Types/Permission.js.map +1 -1
  708. package/build/dist/Types/SerializableObjectDictionary.js +133 -39
  709. package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
  710. package/build/dist/Types/Telemetry/EntityRelationshipType.js +1 -1
  711. package/build/dist/Types/Telemetry/EntitySource.js +39 -0
  712. package/build/dist/Types/Telemetry/EntitySource.js.map +1 -0
  713. package/build/dist/Types/Telemetry/EntityType.js +28 -1
  714. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  715. package/build/dist/Types/Telemetry/EntityTypeGroups.js +57 -0
  716. package/build/dist/Types/Telemetry/EntityTypeGroups.js.map +1 -0
  717. package/build/dist/Types/Workflow/Component.js +21 -0
  718. package/build/dist/Types/Workflow/Component.js.map +1 -1
  719. package/build/dist/Types/Workflow/Components/API.js +35 -0
  720. package/build/dist/Types/Workflow/Components/API.js.map +1 -1
  721. package/build/dist/Types/Workflow/Components/BaseModel.js +68 -26
  722. package/build/dist/Types/Workflow/Components/BaseModel.js.map +1 -1
  723. package/build/dist/Types/Workflow/Components/Discord.js +1 -0
  724. package/build/dist/Types/Workflow/Components/Discord.js.map +1 -1
  725. package/build/dist/Types/Workflow/Components/Email.js +12 -3
  726. package/build/dist/Types/Workflow/Components/Email.js.map +1 -1
  727. package/build/dist/Types/Workflow/Components/JavaScript.js +7 -0
  728. package/build/dist/Types/Workflow/Components/JavaScript.js.map +1 -1
  729. package/build/dist/Types/Workflow/Components/MicrosoftTeams.js +3 -2
  730. package/build/dist/Types/Workflow/Components/MicrosoftTeams.js.map +1 -1
  731. package/build/dist/Types/Workflow/Components/Slack.js +1 -0
  732. package/build/dist/Types/Workflow/Components/Slack.js.map +1 -1
  733. package/build/dist/Types/Workflow/Components/Telegram.js +1 -0
  734. package/build/dist/Types/Workflow/Components/Telegram.js.map +1 -1
  735. package/build/dist/Types/Workflow/StepTrace.js +104 -0
  736. package/build/dist/Types/Workflow/StepTrace.js.map +1 -0
  737. package/build/dist/Types/Workflow/TemplateSyntax.js +338 -0
  738. package/build/dist/Types/Workflow/TemplateSyntax.js.map +1 -0
  739. package/build/dist/Types/Workflow/Templates.js +2111 -0
  740. package/build/dist/Types/Workflow/Templates.js.map +1 -0
  741. package/build/dist/UI/Components/Calendar/Calendar.js +1 -1
  742. package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
  743. package/build/dist/UI/Components/Checkbox/Checkbox.js +1 -1
  744. package/build/dist/UI/Components/Checkbox/Checkbox.js.map +1 -1
  745. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js +126 -0
  746. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js.map +1 -0
  747. package/build/dist/UI/Components/Date/TimeRangePickerDropdown.js +123 -0
  748. package/build/dist/UI/Components/Date/TimeRangePickerDropdown.js.map +1 -0
  749. package/build/dist/UI/Components/Dictionary/Dictionary.js +47 -17
  750. package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
  751. package/build/dist/UI/Components/FormModal/BasicFormModal.js.map +1 -1
  752. package/build/dist/UI/Components/Forms/Fields/ColorPicker.js +52 -13
  753. package/build/dist/UI/Components/Forms/Fields/ColorPicker.js.map +1 -1
  754. package/build/dist/UI/Components/Forms/Fields/IconPicker.js +28 -12
  755. package/build/dist/UI/Components/Forms/Fields/IconPicker.js.map +1 -1
  756. package/build/dist/UI/Components/Forms/Validation.js +44 -0
  757. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  758. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +27 -4
  759. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  760. package/build/dist/UI/Components/Input/Input.js +13 -4
  761. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  762. package/build/dist/UI/Components/KeyboardShortcut/KeyboardKey.js +163 -0
  763. package/build/dist/UI/Components/KeyboardShortcut/KeyboardKey.js.map +1 -0
  764. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcut.js +47 -0
  765. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcut.js.map +1 -0
  766. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +4 -4
  767. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  768. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js +11 -1
  769. package/build/dist/UI/Components/LogsViewer/components/ActiveFilterChips.js.map +1 -1
  770. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js +10 -8
  771. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js.map +1 -1
  772. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +227 -14
  773. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  774. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +5 -108
  775. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  776. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +5 -0
  777. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  778. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js +69 -5
  779. package/build/dist/UI/Components/LogsViewer/components/LogsTable.js.map +1 -1
  780. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +8 -0
  781. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  782. package/build/dist/UI/Components/LogsViewer/types.js.map +1 -1
  783. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +9 -2
  784. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
  785. package/build/dist/UI/Components/Modal/Modal.js +31 -5
  786. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  787. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +8 -21
  788. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  789. package/build/dist/UI/Components/ProjectInvitations/PendingProjectInvitations.js +251 -0
  790. package/build/dist/UI/Components/ProjectInvitations/PendingProjectInvitations.js.map +1 -0
  791. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js +9 -2
  792. package/build/dist/UI/Components/SimpleLogViewer/SimpleLogViewer.js.map +1 -1
  793. package/build/dist/UI/Components/Table/Table.js +27 -15
  794. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  795. package/build/dist/UI/Components/Table/TableBody.js +24 -18
  796. package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
  797. package/build/dist/UI/Components/Table/TableHeader.js +9 -1
  798. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  799. package/build/dist/UI/Components/Table/TableRow.js +29 -21
  800. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  801. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +5 -105
  802. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  803. package/build/dist/UI/Components/Workflow/ArgumentsForm.js +261 -14
  804. package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
  805. package/build/dist/UI/Components/Workflow/Component.js +20 -19
  806. package/build/dist/UI/Components/Workflow/Component.js.map +1 -1
  807. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js +10 -1
  808. package/build/dist/UI/Components/Workflow/ComponentReturnValueViewer.js.map +1 -1
  809. package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js +35 -7
  810. package/build/dist/UI/Components/Workflow/ComponentSettingsModal.js.map +1 -1
  811. package/build/dist/UI/Components/Workflow/ComponentValuePickerModal.js +57 -7
  812. package/build/dist/UI/Components/Workflow/ComponentValuePickerModal.js.map +1 -1
  813. package/build/dist/UI/Components/Workflow/ComponentsModal.js +53 -18
  814. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  815. package/build/dist/UI/Components/Workflow/DocumentationViewer.js +19 -6
  816. package/build/dist/UI/Components/Workflow/DocumentationViewer.js.map +1 -1
  817. package/build/dist/UI/Components/Workflow/GraphLint.js +425 -0
  818. package/build/dist/UI/Components/Workflow/GraphLint.js.map +1 -0
  819. package/build/dist/UI/Components/Workflow/GraphLintSummary.js +231 -0
  820. package/build/dist/UI/Components/Workflow/GraphLintSummary.js.map +1 -0
  821. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +320 -0
  822. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -0
  823. package/build/dist/UI/Components/Workflow/ModelSchema.js +156 -0
  824. package/build/dist/UI/Components/Workflow/ModelSchema.js.map +1 -0
  825. package/build/dist/UI/Components/Workflow/RunForm.js +22 -6
  826. package/build/dist/UI/Components/Workflow/RunForm.js.map +1 -1
  827. package/build/dist/UI/Components/Workflow/RunStatusWatcher.js +76 -0
  828. package/build/dist/UI/Components/Workflow/RunStatusWatcher.js.map +1 -0
  829. package/build/dist/UI/Components/Workflow/StepTraceViewer.js +76 -0
  830. package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -0
  831. package/build/dist/UI/Components/Workflow/UseRunWatch.js +123 -0
  832. package/build/dist/UI/Components/Workflow/UseRunWatch.js.map +1 -0
  833. package/build/dist/UI/Components/Workflow/Utils.js +73 -1
  834. package/build/dist/UI/Components/Workflow/Utils.js.map +1 -1
  835. package/build/dist/UI/Components/Workflow/VariableModal.js +3 -2
  836. package/build/dist/UI/Components/Workflow/VariableModal.js.map +1 -1
  837. package/build/dist/UI/Components/Workflow/Workflow.js +92 -7
  838. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  839. package/build/dist/UI/Components/Workflow/WorkflowIssuesModal.js +99 -0
  840. package/build/dist/UI/Components/Workflow/WorkflowIssuesModal.js.map +1 -0
  841. package/build/dist/UI/Components/Workflow/WorkflowLogModal.js +56 -0
  842. package/build/dist/UI/Components/Workflow/WorkflowLogModal.js.map +1 -0
  843. package/build/dist/UI/Components/Workflow/WorkflowStatusBar.js +92 -0
  844. package/build/dist/UI/Components/Workflow/WorkflowStatusBar.js.map +1 -0
  845. package/build/dist/UI/Types/LayeredDismissal.js +21 -0
  846. package/build/dist/UI/Types/LayeredDismissal.js.map +1 -0
  847. package/build/dist/UI/Types/UseAnchoredFieldPopup.js +74 -1
  848. package/build/dist/UI/Types/UseAnchoredFieldPopup.js.map +1 -1
  849. package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js +9 -0
  850. package/build/dist/UI/Utils/AIChatExport/ConversationMarkdown.js.map +1 -1
  851. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +1 -1
  852. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  853. package/build/dist/UI/Utils/Platform.js +118 -0
  854. package/build/dist/UI/Utils/Platform.js.map +1 -0
  855. package/build/dist/UI/Utils/ProjectInvitationDisplay.js +106 -0
  856. package/build/dist/UI/Utils/ProjectInvitationDisplay.js.map +1 -0
  857. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js +108 -0
  858. package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js.map +1 -0
  859. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +386 -0
  860. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -0
  861. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +661 -126
  862. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  863. package/build/dist/Utils/Telemetry/CrossSignalScope.js +328 -0
  864. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -0
  865. package/build/dist/Utils/Telemetry/EntityKey.js +57 -5
  866. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  867. package/build/dist/Utils/Telemetry/EntityRelationship.js +1 -1
  868. package/jest.config.json +1 -0
  869. package/package.json +1 -1
  870. package/build/dist/Models/DatabaseModels/TelemetryEntity.js.map +0 -1
  871. package/build/dist/Models/DatabaseModels/TelemetryEntityRelationship.js.map +0 -1
  872. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +0 -1
  873. package/build/dist/Server/Services/TelemetryEntityService.js.map +0 -1
@@ -0,0 +1,1536 @@
1
+ import AlertService from "../../../Server/Services/AlertService";
2
+ import AlertSeverityService, {
3
+ Service as AlertSeverityServiceClass,
4
+ } from "../../../Server/Services/AlertSeverityService";
5
+ import DatabaseService from "../../../Server/Services/DatabaseService";
6
+ import IncidentService from "../../../Server/Services/IncidentService";
7
+ import IncidentSeverityService, {
8
+ Service as IncidentSeverityServiceClass,
9
+ } from "../../../Server/Services/IncidentSeverityService";
10
+ import OnCallDutyPolicyExecutionLogTimelineService from "../../../Server/Services/OnCallDutyPolicyExecutionLogTimelineService";
11
+ import ProjectService from "../../../Server/Services/ProjectService";
12
+ import UserNotificationRuleService, {
13
+ FallbackNotificationOutcome,
14
+ } from "../../../Server/Services/UserNotificationRuleService";
15
+ import UserOnCallLogService from "../../../Server/Services/UserOnCallLogService";
16
+ import UserService from "../../../Server/Services/UserService";
17
+ import Queue, { QueueName } from "../../../Server/Infrastructure/Queue";
18
+ import CreateBy from "../../../Server/Types/Database/CreateBy";
19
+ import { OnCreate } from "../../../Server/Types/Database/Hooks";
20
+ import Alert from "../../../Models/DatabaseModels/Alert";
21
+ import AlertSeverity from "../../../Models/DatabaseModels/AlertSeverity";
22
+ import Incident from "../../../Models/DatabaseModels/Incident";
23
+ import IncidentSeverity from "../../../Models/DatabaseModels/IncidentSeverity";
24
+ import UserNotificationRule from "../../../Models/DatabaseModels/UserNotificationRule";
25
+ import UserOnCallLog from "../../../Models/DatabaseModels/UserOnCallLog";
26
+ import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
27
+ import BadDataException from "../../../Types/Exception/BadDataException";
28
+ import NotificationRuleType from "../../../Types/NotificationRule/NotificationRuleType";
29
+ import ObjectID from "../../../Types/ObjectID";
30
+ import OnCallDutyExecutionLogTimelineStatus from "../../../Types/OnCallDutyPolicy/OnCalDutyExecutionLogTimelineStatus";
31
+ import PositiveNumber from "../../../Types/PositiveNumber";
32
+ import UserNotificationEventType from "../../../Types/UserNotification/UserNotificationEventType";
33
+ import UserNotificationExecutionStatus from "../../../Types/UserNotification/UserNotificationExecutionStatus";
34
+ import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
35
+
36
+ /*
37
+ * GAP A — a severity created after a user joined was a severity that user had
38
+ * no notification rule for, and nothing anywhere backfilled one.
39
+ *
40
+ * The default rules a responder gets are written by
41
+ * UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(),
42
+ * whose two severity-shaped halves — createIncidentOnCallRules() and
43
+ * createAlertOnCallRules() — iterate the severities that exist AT THE MOMENT
44
+ * THEY RUN. They run when a member joins a project, when a notification method
45
+ * is verified, and in the MigrateDefaultUserNotificationRule migration. They did
46
+ * NOT run when a severity was created, because neither IncidentSeverityService
47
+ * nor AlertSeverityService defined any create-success hook at all: both stopped
48
+ * at onBeforeCreate, whose entire job is order rearrangement.
49
+ *
50
+ * So "add a Sev4 a year into the project" was a silent paging outage for every
51
+ * existing user: UserOnCallLogService.onCreateSuccess counts rules with
52
+ * { userId, projectId, ruleType, incidentSeverityId }, got zero, wrote
53
+ * "No notification rules found for this user." into an execution log nobody
54
+ * reads, and returned without paging anyone.
55
+ *
56
+ * PHASE 1 CLOSED THIS, on two independent fronts, and this file now pins both:
57
+ *
58
+ * (A) Creating a severity enqueues
59
+ * "OnCallDutyPolicy:BackfillNotificationRulesForNewSeverities" onto the
60
+ * Worker queue. Proven structurally (onCreateSuccess is now an own
61
+ * property on both services, no longer DatabaseService's placeholder) and
62
+ * behaviourally (drive the hooks; assert the enqueue, its queue, its name
63
+ * and its payload). The fan-out itself stays OUT of the request — a
64
+ * project can hold thousands of responders — so "no rules written inline"
65
+ * is still asserted, but it no longer means "no backfill".
66
+ * (B) Rule creation is still severity-snapshot-driven, and that is fine now
67
+ * that something else revisits the snapshot. This section is unchanged: it
68
+ * documents why the backfill has to exist.
69
+ * (C) The runtime hole. A user with rules for [A, B] and a project with
70
+ * severities [A, B, C] still has zero rules matching a C-severity
71
+ * incident — but the page is no longer dropped. UserOnCallLogService now
72
+ * reaches for the verified-method fallback instead of the dead-end, so the
73
+ * responder is notified and the log says so.
74
+ *
75
+ * Assertions that used to carry the "GAP A" banner now carry "GAP A CLOSED" and
76
+ * state the post-Phase-1 behaviour.
77
+ */
78
+
79
+ /*
80
+ * Mirrors the private constant in IncidentSeverityService / AlertSeverityService,
81
+ * which in turn mirrors the RunCron job name in
82
+ * App/FeatureSet/Workers/Jobs/OnCallDutyPolicy/BackfillNotificationRulesForNewSeverities.ts.
83
+ * If a rename ever misses one of the three, this is where it surfaces.
84
+ */
85
+ const BACKFILL_JOB_NAME: string =
86
+ "OnCallDutyPolicy:BackfillNotificationRulesForNewSeverities";
87
+
88
+ const PROJECT_ID: ObjectID = new ObjectID("project-1");
89
+ const USER_ID: ObjectID = new ObjectID("user-1");
90
+ const USER_EMAIL_ID: ObjectID = new ObjectID("user-email-1");
91
+ const LOG_ID: ObjectID = new ObjectID("oncall-log-1");
92
+ const TIMELINE_ID: ObjectID = new ObjectID("timeline-1");
93
+ const INCIDENT_ID: ObjectID = new ObjectID("incident-1");
94
+ const ALERT_ID: ObjectID = new ObjectID("alert-1");
95
+
96
+ // The two severities that existed when the user joined, and the late arrival.
97
+ const SEV_A: ObjectID = new ObjectID("incident-severity-A");
98
+ const SEV_B: ObjectID = new ObjectID("incident-severity-B");
99
+ const SEV_C: ObjectID = new ObjectID("incident-severity-C-added-later");
100
+
101
+ const ALERT_SEV_A: ObjectID = new ObjectID("alert-severity-A");
102
+ const ALERT_SEV_B: ObjectID = new ObjectID("alert-severity-B");
103
+ const ALERT_SEV_C: ObjectID = new ObjectID("alert-severity-C-added-later");
104
+
105
+ /*
106
+ * ------------------------------------------------------------------------- *
107
+ * A tiny in-memory stand-in for the UserNotificationRule table.
108
+ *
109
+ * Both halves of the gap are read through it: section B writes into it via the
110
+ * real createIncidentOnCallRules()/createAlertOnCallRules() code paths, and
111
+ * section C then queries it with exactly the shape UserOnCallLogService uses.
112
+ * That is deliberate — the coverage hole is only meaningful if the rows the
113
+ * writer produced are the rows the reader misses.
114
+ * -------------------------------------------------------------------------
115
+ */
116
+
117
+ interface StoredRule {
118
+ id: ObjectID;
119
+ projectId: string | undefined;
120
+ userId: string | undefined;
121
+ ruleType: NotificationRuleType | undefined;
122
+ incidentSeverityId: string | undefined;
123
+ alertSeverityId: string | undefined;
124
+ notifyAfterMinutes: number | undefined;
125
+ userEmailId: string | undefined;
126
+ isOptOut: boolean | undefined;
127
+ }
128
+
129
+ let ruleStore: Array<StoredRule> = [];
130
+
131
+ function toIdString(value: unknown): string | undefined {
132
+ if (value === undefined || value === null) {
133
+ return undefined;
134
+ }
135
+
136
+ return String(value);
137
+ }
138
+
139
+ /*
140
+ * Match a stored row against a service query. A key the query does not carry is
141
+ * not a constraint — that mirrors how the real queries are built, where
142
+ * createSingleRule simply omits the severity columns and UserOnCallLogService
143
+ * passes `alertSeverityId: undefined` on the incident path.
144
+ */
145
+ function ruleMatchesQuery(
146
+ rule: StoredRule,
147
+ query: Record<string, unknown>,
148
+ ): boolean {
149
+ const idFields: Array<keyof StoredRule> = [
150
+ "projectId",
151
+ "userId",
152
+ "incidentSeverityId",
153
+ "alertSeverityId",
154
+ "userEmailId",
155
+ ];
156
+
157
+ for (const field of idFields) {
158
+ const expected: string | undefined = toIdString(query[field as string]);
159
+
160
+ if (expected !== undefined && toIdString(rule[field]) !== expected) {
161
+ return false;
162
+ }
163
+ }
164
+
165
+ const expectedRuleType: unknown = query["ruleType"];
166
+
167
+ if (expectedRuleType !== undefined && rule.ruleType !== expectedRuleType) {
168
+ return false;
169
+ }
170
+
171
+ const expectedNotifyAfterMinutes: unknown = query["notifyAfterMinutes"];
172
+
173
+ if (
174
+ expectedNotifyAfterMinutes !== undefined &&
175
+ rule.notifyAfterMinutes !== expectedNotifyAfterMinutes
176
+ ) {
177
+ return false;
178
+ }
179
+
180
+ /*
181
+ * isOptOut appears in queries in TWO different shapes, and conflating them
182
+ * makes this matcher reject everything.
183
+ *
184
+ * - As a literal `true`: the no-rule path's opt-out lookup, asking whether
185
+ * this exact (ruleType x severity) cell was deliberately muted.
186
+ * - As a PREDICATE OBJECT: every counting and execution query excludes
187
+ * opt-out rows with notOptOutRuleQuery(), which is
188
+ * QueryHelper.notInOrNull(["true"]) - a TypeORM operator, not a boolean.
189
+ * It is deliberately null-tolerant: isOptOut is nullable and every rule
190
+ * written before the column existed has it NULL, so a plain
191
+ * `isOptOut: false` would match none of them and quietly exclude every
192
+ * pre-existing rule from paging.
193
+ *
194
+ * A boolean is compared directly; anything else is the exclusion predicate,
195
+ * which a row satisfies precisely when it is not an opt-out.
196
+ */
197
+ const expectedIsOptOut: unknown = query["isOptOut"];
198
+
199
+ if (expectedIsOptOut !== undefined) {
200
+ if (typeof expectedIsOptOut === "boolean") {
201
+ if (Boolean(rule.isOptOut) !== expectedIsOptOut) {
202
+ return false;
203
+ }
204
+ } else if (rule.isOptOut === true) {
205
+ return false;
206
+ }
207
+ }
208
+
209
+ return true;
210
+ }
211
+
212
+ function matchingRules(query: Record<string, unknown>): Array<StoredRule> {
213
+ return ruleStore.filter((rule: StoredRule): boolean => {
214
+ return ruleMatchesQuery(rule, query);
215
+ });
216
+ }
217
+
218
+ /*
219
+ * Remove a column the way a request that simply omitted it would.
220
+ *
221
+ * Takes `unknown` and narrows inside, the way callHook below does. Callers hand
222
+ * it a model INSTANCE, and a class with declared properties is not assignable to
223
+ * Record<string, unknown> under this repo's strict config - while `object` is
224
+ * banned by the lint rules. Widening at the boundary satisfies both.
225
+ */
226
+ function unsetColumn(model: unknown, column: string): void {
227
+ Reflect.deleteProperty(model as Record<string, unknown>, column);
228
+ }
229
+
230
+ // Calls a protected hook without widening the service's public surface.
231
+ function callHook(
232
+ service: unknown,
233
+ name: string,
234
+ ...args: Array<unknown>
235
+ ): Promise<unknown> {
236
+ const hooks: Record<
237
+ string,
238
+ (...hookArgs: Array<unknown>) => Promise<unknown>
239
+ > = service as Record<
240
+ string,
241
+ (...hookArgs: Array<unknown>) => Promise<unknown>
242
+ >;
243
+
244
+ return hooks[name]!.apply(service, args);
245
+ }
246
+
247
+ // Same reason as unsetColumn: callers pass a class prototype, not a map.
248
+ function ownHookNames(prototype: unknown): Array<string> {
249
+ return Object.getOwnPropertyNames(prototype as Record<string, unknown>)
250
+ .filter((name: string): boolean => {
251
+ return name.startsWith("on");
252
+ })
253
+ .sort();
254
+ }
255
+
256
+ function incidentSeverityRows(ids: Array<ObjectID>): Array<IncidentSeverity> {
257
+ return ids.map((id: ObjectID): IncidentSeverity => {
258
+ const severity: IncidentSeverity = new IncidentSeverity();
259
+ severity._id = id.toString();
260
+ severity.projectId = PROJECT_ID;
261
+
262
+ return severity;
263
+ });
264
+ }
265
+
266
+ function alertSeverityRows(ids: Array<ObjectID>): Array<AlertSeverity> {
267
+ return ids.map((id: ObjectID): AlertSeverity => {
268
+ const severity: AlertSeverity = new AlertSeverity();
269
+ severity._id = id.toString();
270
+ severity.projectId = PROJECT_ID;
271
+
272
+ return severity;
273
+ });
274
+ }
275
+
276
+ /* Wire the store into the service's own read/write helpers. */
277
+ function stubUserNotificationRuleStore(): void {
278
+ jest
279
+ .spyOn(UserNotificationRuleService, "findOneBy")
280
+ .mockImplementation(((data: {
281
+ query: Record<string, unknown>;
282
+ }): Promise<UserNotificationRule | null> => {
283
+ const match: StoredRule | undefined = matchingRules(data.query)[0];
284
+
285
+ if (!match) {
286
+ return Promise.resolve(null);
287
+ }
288
+
289
+ const model: UserNotificationRule = new UserNotificationRule();
290
+ model._id = match.id.toString();
291
+
292
+ return Promise.resolve(model);
293
+ }) as never);
294
+
295
+ jest.spyOn(UserNotificationRuleService, "findBy").mockImplementation(((data: {
296
+ query: Record<string, unknown>;
297
+ }): Promise<Array<UserNotificationRule>> => {
298
+ return Promise.resolve(
299
+ matchingRules(data.query).map(
300
+ (stored: StoredRule): UserNotificationRule => {
301
+ const model: UserNotificationRule = new UserNotificationRule();
302
+ model._id = stored.id.toString();
303
+
304
+ return model;
305
+ },
306
+ ),
307
+ );
308
+ }) as never);
309
+
310
+ jest
311
+ .spyOn(UserNotificationRuleService, "countBy")
312
+ .mockImplementation(((data: {
313
+ query: Record<string, unknown>;
314
+ }): Promise<PositiveNumber> => {
315
+ return Promise.resolve(
316
+ new PositiveNumber(matchingRules(data.query).length),
317
+ );
318
+ }) as never);
319
+
320
+ jest.spyOn(UserNotificationRuleService, "create").mockImplementation(((data: {
321
+ data: UserNotificationRule;
322
+ }): Promise<UserNotificationRule> => {
323
+ const model: UserNotificationRule = data.data;
324
+ const id: ObjectID = new ObjectID(`rule-${ruleStore.length + 1}`);
325
+ model._id = id.toString();
326
+
327
+ ruleStore.push({
328
+ id: id,
329
+ projectId: toIdString(model.projectId),
330
+ userId: toIdString(model.userId),
331
+ ruleType: model.ruleType,
332
+ incidentSeverityId: toIdString(model.incidentSeverityId),
333
+ alertSeverityId: toIdString(model.alertSeverityId),
334
+ notifyAfterMinutes: model.notifyAfterMinutes,
335
+ userEmailId: toIdString(model.userEmailId),
336
+ isOptOut: model.isOptOut,
337
+ });
338
+
339
+ return Promise.resolve(model);
340
+ }) as never);
341
+ }
342
+
343
+ /* The severities the project has AT THIS MOMENT. */
344
+ function stubSeverities(
345
+ incidentSeverityIds: Array<ObjectID>,
346
+ alertSeverityIds: Array<ObjectID>,
347
+ ): void {
348
+ jest
349
+ .spyOn(IncidentSeverityService, "findBy")
350
+ .mockResolvedValue(incidentSeverityRows(incidentSeverityIds) as never);
351
+ jest
352
+ .spyOn(AlertSeverityService, "findBy")
353
+ .mockResolvedValue(alertSeverityRows(alertSeverityIds) as never);
354
+ }
355
+
356
+ function runDefaults(): Promise<void> {
357
+ return UserNotificationRuleService.addDefaultNotificationRulesForVerifiedMethod(
358
+ {
359
+ projectId: PROJECT_ID,
360
+ userId: USER_ID,
361
+ notificationMethod: {
362
+ userEmailId: USER_EMAIL_ID,
363
+ },
364
+ },
365
+ );
366
+ }
367
+
368
+ function rulesOfType(ruleType: NotificationRuleType): Array<StoredRule> {
369
+ return ruleStore.filter((rule: StoredRule): boolean => {
370
+ return rule.ruleType === ruleType;
371
+ });
372
+ }
373
+
374
+ function incidentSeverityIdsCovered(): Array<string | undefined> {
375
+ return rulesOfType(NotificationRuleType.ON_CALL_EXECUTED_INCIDENT).map(
376
+ (rule: StoredRule): string | undefined => {
377
+ return rule.incidentSeverityId;
378
+ },
379
+ );
380
+ }
381
+
382
+ function alertSeverityIdsCovered(): Array<string | undefined> {
383
+ return rulesOfType(NotificationRuleType.ON_CALL_EXECUTED_ALERT).map(
384
+ (rule: StoredRule): string | undefined => {
385
+ return rule.alertSeverityId;
386
+ },
387
+ );
388
+ }
389
+
390
+ beforeEach(() => {
391
+ ruleStore = [];
392
+ });
393
+
394
+ afterEach(() => {
395
+ jest.restoreAllMocks();
396
+ });
397
+
398
+ /*
399
+ * ========================================================================= *
400
+ * (A) Creating a severity now queues the backfill.
401
+ *
402
+ * GAP A CLOSED IN PHASE 1. This section used to prove the opposite: that
403
+ * neither severity service had any create-success hook at all, and that
404
+ * committing a severity row was followed by exactly nothing. Both services now
405
+ * override onCreateSuccess and enqueue
406
+ * "OnCallDutyPolicy:BackfillNotificationRulesForNewSeverities" onto the Worker
407
+ * queue.
408
+ *
409
+ * Note what did NOT change, and why it is still asserted: no rule is written
410
+ * inline. That is deliberate rather than residual. A project can hold thousands
411
+ * of responders and this hook runs inside the request that created the
412
+ * severity, so the fan-out belongs to the worker. "No inline rule creation" and
413
+ * "no backfill" used to be the same observation; they are now opposites, and
414
+ * the enqueue assertion is what tells them apart.
415
+ * =========================================================================
416
+ */
417
+
418
+ describe("GAP A CLOSED - IncidentSeverityService queues the rule backfill on create", () => {
419
+ let createSpy: jest.SpyInstance;
420
+ let addDefaultsForMethodSpy: jest.SpyInstance;
421
+ let addDefaultsForUserSpy: jest.SpyInstance;
422
+ let addJobSpy: jest.SpyInstance;
423
+
424
+ beforeEach(() => {
425
+ /*
426
+ * onBeforeCreate's only real work is order rearrangement, which reads and
427
+ * rewrites sibling rows. Stub both so the hook is drivable without a
428
+ * database.
429
+ */
430
+ jest
431
+ .spyOn(IncidentSeverityService, "findBy")
432
+ .mockResolvedValue([] as never);
433
+ jest
434
+ .spyOn(IncidentSeverityService, "updateOneBy")
435
+ .mockResolvedValue(0 as never);
436
+
437
+ // The queue is the hook's only side effect; never reach Redis for it.
438
+ addJobSpy = jest.spyOn(Queue, "addJob").mockResolvedValue({} as never);
439
+
440
+ createSpy = jest
441
+ .spyOn(UserNotificationRuleService, "create")
442
+ .mockResolvedValue(new UserNotificationRule() as never);
443
+ addDefaultsForMethodSpy = jest
444
+ .spyOn(
445
+ UserNotificationRuleService,
446
+ "addDefaultNotificationRulesForVerifiedMethod",
447
+ )
448
+ .mockResolvedValue(undefined as never);
449
+ addDefaultsForUserSpy = jest
450
+ .spyOn(UserNotificationRuleService, "addDefaultNotificationRuleForUser")
451
+ .mockResolvedValue(undefined as never);
452
+ });
453
+
454
+ function createBySeverity(): CreateBy<IncidentSeverity> {
455
+ const severity: IncidentSeverity = new IncidentSeverity();
456
+ severity.name = "Sev4";
457
+ severity.order = 4;
458
+ severity.projectId = PROJECT_ID;
459
+
460
+ return {
461
+ data: severity,
462
+ props: { isRoot: true },
463
+ } as CreateBy<IncidentSeverity>;
464
+ }
465
+
466
+ function createdSeverity(): IncidentSeverity {
467
+ const created: IncidentSeverity = new IncidentSeverity();
468
+ created._id = SEV_C.toString();
469
+ created.projectId = PROJECT_ID;
470
+
471
+ return created;
472
+ }
473
+
474
+ function expectNoInlineRuleCreation(): void {
475
+ expect(createSpy).not.toHaveBeenCalled();
476
+ expect(addDefaultsForMethodSpy).not.toHaveBeenCalled();
477
+ expect(addDefaultsForUserSpy).not.toHaveBeenCalled();
478
+ }
479
+
480
+ /*
481
+ * GAP A CLOSED - onCreateSuccess is the hook Phase 1 added, so it now appears
482
+ * in this list. The rest of the list is unchanged: the backfill hangs off the
483
+ * success hook, not off any of the before-hooks.
484
+ */
485
+ test("it overrides onCreateSuccess alongside its ordering hooks", () => {
486
+ expect(ownHookNames(IncidentSeverityServiceClass.prototype)).toEqual([
487
+ "onBeforeCreate",
488
+ "onBeforeDelete",
489
+ "onBeforeUpdate",
490
+ "onCreateSuccess",
491
+ "onDeleteSuccess",
492
+ ]);
493
+ });
494
+
495
+ /*
496
+ * GAP A CLOSED - the inverse of the original assertion. Sharing
497
+ * DatabaseService's identity was the precise statement of "does nothing"; a
498
+ * distinct own property is the precise statement that it now does something.
499
+ */
500
+ test("onCreateSuccess is no longer DatabaseService's do-nothing placeholder", () => {
501
+ const proto: Record<string, unknown> =
502
+ IncidentSeverityServiceClass.prototype as unknown as Record<
503
+ string,
504
+ unknown
505
+ >;
506
+ const base: Record<string, unknown> =
507
+ DatabaseService.prototype as unknown as Record<string, unknown>;
508
+
509
+ expect(proto["onCreateSuccess"]).not.toBe(base["onCreateSuccess"]);
510
+ expect(
511
+ Object.prototype.hasOwnProperty.call(
512
+ IncidentSeverityServiceClass.prototype,
513
+ "onCreateSuccess",
514
+ ),
515
+ ).toBe(true);
516
+ });
517
+
518
+ test("it does not override onCreateError either, so there is no rule work on the failure path", () => {
519
+ expect(
520
+ Object.prototype.hasOwnProperty.call(
521
+ IncidentSeverityServiceClass.prototype,
522
+ "onCreateError",
523
+ ),
524
+ ).toBe(false);
525
+ });
526
+
527
+ /*
528
+ * GAP A CLOSED - the backfill hangs off onCreateSuccess, so the before-hook
529
+ * on its own still queues nothing and writes nothing. A severity that fails
530
+ * validation must not leave a backfill job behind for a row that was never
531
+ * committed.
532
+ */
533
+ test("driving onBeforeCreate alone neither writes rules nor queues the backfill", async () => {
534
+ await callHook(
535
+ IncidentSeverityService,
536
+ "onBeforeCreate",
537
+ createBySeverity(),
538
+ );
539
+
540
+ expectNoInlineRuleCreation();
541
+ expect(addJobSpy).not.toHaveBeenCalled();
542
+ });
543
+
544
+ test("onBeforeCreate only rearranges sibling order - that is its whole job", async () => {
545
+ const findBySpy: jest.SpyInstance = jest.spyOn(
546
+ IncidentSeverityService,
547
+ "findBy",
548
+ );
549
+
550
+ await callHook(
551
+ IncidentSeverityService,
552
+ "onBeforeCreate",
553
+ createBySeverity(),
554
+ );
555
+
556
+ expect(findBySpy).toHaveBeenCalledTimes(1);
557
+ expectNoInlineRuleCreation();
558
+ });
559
+
560
+ /*
561
+ * GAP A CLOSED - driving the full create sequence is the behavioural proof.
562
+ * The severity row is committed and a backfill job follows it, on the Worker
563
+ * queue, named for the cron that owns it.
564
+ */
565
+ test("the full create sequence queues the backfill job", async () => {
566
+ const createBy: CreateBy<IncidentSeverity> = createBySeverity();
567
+
568
+ const onCreate: OnCreate<IncidentSeverity> = (await callHook(
569
+ IncidentSeverityService,
570
+ "onBeforeCreate",
571
+ createBy,
572
+ )) as OnCreate<IncidentSeverity>;
573
+
574
+ const created: IncidentSeverity = createdSeverity();
575
+
576
+ const returned: unknown = await callHook(
577
+ IncidentSeverityService,
578
+ "onCreateSuccess",
579
+ onCreate,
580
+ created,
581
+ );
582
+
583
+ // The hook still hands the created item straight back.
584
+ expect(returned).toBe(created);
585
+
586
+ expect(addJobSpy).toHaveBeenCalledTimes(1);
587
+ const call: Array<unknown> = addJobSpy.mock.calls[0]!;
588
+ expect(call[0]).toBe(QueueName.Worker);
589
+ expect(call[2]).toBe(BACKFILL_JOB_NAME);
590
+
591
+ // Still nothing inline - the fan-out is the worker's job, not the request's.
592
+ expectNoInlineRuleCreation();
593
+ });
594
+
595
+ /*
596
+ * GAP A CLOSED - a queue that is unreachable must not take the severity down
597
+ * with it. The scheduled sweep inside the backfill job re-scans recently
598
+ * created severities, so a dropped enqueue costs latency, not coverage.
599
+ */
600
+ test("an enqueue failure is swallowed and the created item is still returned", async () => {
601
+ addJobSpy.mockRejectedValue(new Error("redis is down") as never);
602
+
603
+ const created: IncidentSeverity = createdSeverity();
604
+
605
+ const returned: unknown = await callHook(
606
+ IncidentSeverityService,
607
+ "onCreateSuccess",
608
+ { createBy: createBySeverity(), carryForward: null },
609
+ created,
610
+ );
611
+
612
+ expect(returned).toBe(created);
613
+ });
614
+
615
+ test("a severity with no order is rejected, and still nothing touches rules", async () => {
616
+ const createBy: CreateBy<IncidentSeverity> = createBySeverity();
617
+ unsetColumn(createBy.data, "order");
618
+
619
+ await expect(
620
+ callHook(IncidentSeverityService, "onBeforeCreate", createBy),
621
+ ).rejects.toBeInstanceOf(BadDataException);
622
+
623
+ expectNoInlineRuleCreation();
624
+ });
625
+
626
+ test("a severity with no projectId is rejected, and still nothing touches rules", async () => {
627
+ const createBy: CreateBy<IncidentSeverity> = createBySeverity();
628
+ unsetColumn(createBy.data, "projectId");
629
+
630
+ await expect(
631
+ callHook(IncidentSeverityService, "onBeforeCreate", createBy),
632
+ ).rejects.toBeInstanceOf(BadDataException);
633
+
634
+ expectNoInlineRuleCreation();
635
+ });
636
+
637
+ /*
638
+ * GAP A CLOSED - the user-visible consequence, inverted. However many people
639
+ * are already in the project, creating a severity used to consider none of
640
+ * them. It still enumerates none of them HERE, because it hands the whole
641
+ * question to a job that carries the project and severity that changed.
642
+ */
643
+ test("the queued job names the project and severity whose responders need covering", async () => {
644
+ const createBy: CreateBy<IncidentSeverity> = createBySeverity();
645
+
646
+ const onCreate: OnCreate<IncidentSeverity> = (await callHook(
647
+ IncidentSeverityService,
648
+ "onBeforeCreate",
649
+ createBy,
650
+ )) as OnCreate<IncidentSeverity>;
651
+
652
+ await callHook(
653
+ IncidentSeverityService,
654
+ "onCreateSuccess",
655
+ onCreate,
656
+ createdSeverity(),
657
+ );
658
+
659
+ expect(addJobSpy).toHaveBeenCalledTimes(1);
660
+ const payload: Record<string, unknown> = addJobSpy.mock
661
+ .calls[0]![3] as Record<string, unknown>;
662
+
663
+ expect(payload["projectId"]).toBe(PROJECT_ID.toString());
664
+ expect(payload["incidentSeverityId"]).toBe(SEV_C.toString());
665
+
666
+ // The request itself still writes no rules and reads no users.
667
+ expect(addDefaultsForMethodSpy).toHaveBeenCalledTimes(0);
668
+ expect(createSpy).toHaveBeenCalledTimes(0);
669
+ });
670
+ });
671
+
672
+ describe("GAP A CLOSED - AlertSeverityService queues the rule backfill on create", () => {
673
+ let createSpy: jest.SpyInstance;
674
+ let addDefaultsForMethodSpy: jest.SpyInstance;
675
+ let addDefaultsForUserSpy: jest.SpyInstance;
676
+ let addJobSpy: jest.SpyInstance;
677
+
678
+ beforeEach(() => {
679
+ jest.spyOn(AlertSeverityService, "findBy").mockResolvedValue([] as never);
680
+ jest
681
+ .spyOn(AlertSeverityService, "updateOneBy")
682
+ .mockResolvedValue(0 as never);
683
+
684
+ addJobSpy = jest.spyOn(Queue, "addJob").mockResolvedValue({} as never);
685
+
686
+ createSpy = jest
687
+ .spyOn(UserNotificationRuleService, "create")
688
+ .mockResolvedValue(new UserNotificationRule() as never);
689
+ addDefaultsForMethodSpy = jest
690
+ .spyOn(
691
+ UserNotificationRuleService,
692
+ "addDefaultNotificationRulesForVerifiedMethod",
693
+ )
694
+ .mockResolvedValue(undefined as never);
695
+ addDefaultsForUserSpy = jest
696
+ .spyOn(UserNotificationRuleService, "addDefaultNotificationRuleForUser")
697
+ .mockResolvedValue(undefined as never);
698
+ });
699
+
700
+ function createBySeverity(): CreateBy<AlertSeverity> {
701
+ const severity: AlertSeverity = new AlertSeverity();
702
+ severity.name = "Sev4";
703
+ severity.order = 4;
704
+ severity.projectId = PROJECT_ID;
705
+
706
+ return {
707
+ data: severity,
708
+ props: { isRoot: true },
709
+ } as CreateBy<AlertSeverity>;
710
+ }
711
+
712
+ function expectNoInlineRuleCreation(): void {
713
+ expect(createSpy).not.toHaveBeenCalled();
714
+ expect(addDefaultsForMethodSpy).not.toHaveBeenCalled();
715
+ expect(addDefaultsForUserSpy).not.toHaveBeenCalled();
716
+ }
717
+
718
+ /*
719
+ * GAP A CLOSED - the alert half moves in lockstep with the incident half.
720
+ */
721
+ test("it overrides onCreateSuccess alongside its ordering hooks", () => {
722
+ expect(ownHookNames(AlertSeverityServiceClass.prototype)).toEqual([
723
+ "onBeforeCreate",
724
+ "onBeforeDelete",
725
+ "onBeforeUpdate",
726
+ "onCreateSuccess",
727
+ "onDeleteSuccess",
728
+ ]);
729
+ });
730
+
731
+ /*
732
+ * GAP A CLOSED - the inverse of the original assertion.
733
+ */
734
+ test("onCreateSuccess is no longer DatabaseService's do-nothing placeholder", () => {
735
+ const proto: Record<string, unknown> =
736
+ AlertSeverityServiceClass.prototype as unknown as Record<string, unknown>;
737
+ const base: Record<string, unknown> =
738
+ DatabaseService.prototype as unknown as Record<string, unknown>;
739
+
740
+ expect(proto["onCreateSuccess"]).not.toBe(base["onCreateSuccess"]);
741
+ expect(
742
+ Object.prototype.hasOwnProperty.call(
743
+ AlertSeverityServiceClass.prototype,
744
+ "onCreateSuccess",
745
+ ),
746
+ ).toBe(true);
747
+ });
748
+
749
+ /*
750
+ * GAP A CLOSED - the alert payload carries alertSeverityId, so the job can
751
+ * tell which of the two severity tables changed without guessing.
752
+ */
753
+ test("the full create sequence queues the backfill job for the alert severity", async () => {
754
+ const createBy: CreateBy<AlertSeverity> = createBySeverity();
755
+
756
+ const onCreate: OnCreate<AlertSeverity> = (await callHook(
757
+ AlertSeverityService,
758
+ "onBeforeCreate",
759
+ createBy,
760
+ )) as OnCreate<AlertSeverity>;
761
+
762
+ const created: AlertSeverity = new AlertSeverity();
763
+ created._id = ALERT_SEV_C.toString();
764
+ created.projectId = PROJECT_ID;
765
+
766
+ const returned: unknown = await callHook(
767
+ AlertSeverityService,
768
+ "onCreateSuccess",
769
+ onCreate,
770
+ created,
771
+ );
772
+
773
+ expect(returned).toBe(created);
774
+
775
+ expect(addJobSpy).toHaveBeenCalledTimes(1);
776
+ const call: Array<unknown> = addJobSpy.mock.calls[0]!;
777
+ expect(call[0]).toBe(QueueName.Worker);
778
+ expect(call[2]).toBe(BACKFILL_JOB_NAME);
779
+
780
+ const payload: Record<string, unknown> = call[3] as Record<string, unknown>;
781
+ expect(payload["projectId"]).toBe(PROJECT_ID.toString());
782
+ expect(payload["alertSeverityId"]).toBe(ALERT_SEV_C.toString());
783
+
784
+ expectNoInlineRuleCreation();
785
+ });
786
+
787
+ test("a severity with no order is rejected, and still nothing touches rules", async () => {
788
+ const createBy: CreateBy<AlertSeverity> = createBySeverity();
789
+ unsetColumn(createBy.data, "order");
790
+
791
+ await expect(
792
+ callHook(AlertSeverityService, "onBeforeCreate", createBy),
793
+ ).rejects.toBeInstanceOf(BadDataException);
794
+
795
+ expectNoInlineRuleCreation();
796
+ });
797
+
798
+ test("a severity with no projectId is rejected, and still nothing touches rules", async () => {
799
+ const createBy: CreateBy<AlertSeverity> = createBySeverity();
800
+ unsetColumn(createBy.data, "projectId");
801
+
802
+ await expect(
803
+ callHook(AlertSeverityService, "onBeforeCreate", createBy),
804
+ ).rejects.toBeInstanceOf(BadDataException);
805
+
806
+ expectNoInlineRuleCreation();
807
+ });
808
+ });
809
+
810
+ /*
811
+ * ========================================================================= *
812
+ * (B) Rule creation is a snapshot of the severities that exist at call time.
813
+ *
814
+ * Unchanged by Phase 1, and deliberately so: the fix was not to make this
815
+ * method clairvoyant, it was to arrange for something to call it again. Every
816
+ * assertion here still describes today's behaviour exactly.
817
+ * =========================================================================
818
+ */
819
+
820
+ describe("GAP A CLOSED - default rules are still a snapshot of the severities that exist at call time", () => {
821
+ beforeEach(() => {
822
+ stubUserNotificationRuleStore();
823
+ });
824
+
825
+ test("a two-severity project produces exactly one incident rule per existing severity", async () => {
826
+ stubSeverities([SEV_A, SEV_B], []);
827
+
828
+ await runDefaults();
829
+
830
+ expect(incidentSeverityIdsCovered()).toEqual([
831
+ SEV_A.toString(),
832
+ SEV_B.toString(),
833
+ ]);
834
+ });
835
+
836
+ test("a severity that does not exist yet gets no rule - there is nothing to iterate", async () => {
837
+ stubSeverities([SEV_A, SEV_B], []);
838
+
839
+ await runDefaults();
840
+
841
+ expect(incidentSeverityIdsCovered()).not.toContain(SEV_C.toString());
842
+ });
843
+
844
+ test("alert severities behave identically", async () => {
845
+ stubSeverities([], [ALERT_SEV_A, ALERT_SEV_B]);
846
+
847
+ await runDefaults();
848
+
849
+ expect(alertSeverityIdsCovered()).toEqual([
850
+ ALERT_SEV_A.toString(),
851
+ ALERT_SEV_B.toString(),
852
+ ]);
853
+ expect(alertSeverityIdsCovered()).not.toContain(ALERT_SEV_C.toString());
854
+ });
855
+
856
+ test("each severity rule is an immediate rule of the right type bound to the verified method", async () => {
857
+ stubSeverities([SEV_A], [ALERT_SEV_A]);
858
+
859
+ await runDefaults();
860
+
861
+ const incidentRule: StoredRule = rulesOfType(
862
+ NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
863
+ )[0]!;
864
+
865
+ expect(incidentRule.projectId).toBe(PROJECT_ID.toString());
866
+ expect(incidentRule.userId).toBe(USER_ID.toString());
867
+ expect(incidentRule.userEmailId).toBe(USER_EMAIL_ID.toString());
868
+ expect(incidentRule.notifyAfterMinutes).toBe(0);
869
+ expect(incidentRule.incidentSeverityId).toBe(SEV_A.toString());
870
+ expect(incidentRule.alertSeverityId).toBeUndefined();
871
+
872
+ const alertRule: StoredRule = rulesOfType(
873
+ NotificationRuleType.ON_CALL_EXECUTED_ALERT,
874
+ )[0]!;
875
+
876
+ expect(alertRule.alertSeverityId).toBe(ALERT_SEV_A.toString());
877
+ expect(alertRule.incidentSeverityId).toBeUndefined();
878
+ expect(alertRule.notifyAfterMinutes).toBe(0);
879
+ });
880
+
881
+ test("only the two go-on/off-call rule types survive a project with no severities", async () => {
882
+ /*
883
+ * GAP G CLOSED - the two EPISODE rule types are severity-scoped now.
884
+ *
885
+ * They used to be created by createSingleRule, which sets ruleType and
886
+ * notifyAfterMinutes and no severity at all. That produced exactly one row
887
+ * per rule type carrying a NULL severity - and UserOnCallLogService counts
888
+ * episode rules filtered by a concrete severity id, so NULL never matched
889
+ * and every one of those "defaults" was dead. Worse, both episode pages
890
+ * scope their table by severity id, so the rows were invisible to the user
891
+ * who owned them: unmatchable AND unfixable.
892
+ *
893
+ * So with zero severities in the project there is now nothing to scope an
894
+ * episode rule TO, and none are written. Only WHEN_USER_GOES_ON_CALL and
895
+ * WHEN_USER_GOES_OFF_CALL remain genuinely severity-less, because "I went
896
+ * on call" is not an event that has a severity.
897
+ */
898
+ stubSeverities([], []);
899
+
900
+ await runDefaults();
901
+
902
+ expect(
903
+ rulesOfType(NotificationRuleType.ON_CALL_EXECUTED_ALERT_EPISODE),
904
+ ).toHaveLength(0);
905
+ expect(
906
+ rulesOfType(NotificationRuleType.ON_CALL_EXECUTED_INCIDENT_EPISODE),
907
+ ).toHaveLength(0);
908
+ expect(
909
+ rulesOfType(NotificationRuleType.WHEN_USER_GOES_ON_CALL),
910
+ ).toHaveLength(1);
911
+ expect(
912
+ rulesOfType(NotificationRuleType.WHEN_USER_GOES_OFF_CALL),
913
+ ).toHaveLength(1);
914
+ });
915
+
916
+ test("a project with no severities yields only the two go-on/off-call rules", async () => {
917
+ stubSeverities([], []);
918
+
919
+ await runDefaults();
920
+
921
+ expect(ruleStore).toHaveLength(2);
922
+ expect(incidentSeverityIdsCovered()).toEqual([]);
923
+ expect(alertSeverityIdsCovered()).toEqual([]);
924
+ });
925
+
926
+ test("two incident and two alert severities yield 2 + 2 + 2 + 2 + 2 rows", async () => {
927
+ /*
928
+ * Per severity: one incident rule, one alert rule, one incident-episode
929
+ * rule and one alert-episode rule - eight in total across two of each
930
+ * severity - plus the two severity-less go-on/off-call rules.
931
+ */
932
+ stubSeverities([SEV_A, SEV_B], [ALERT_SEV_A, ALERT_SEV_B]);
933
+
934
+ await runDefaults();
935
+
936
+ expect(ruleStore).toHaveLength(10);
937
+ expect(
938
+ rulesOfType(NotificationRuleType.ON_CALL_EXECUTED_INCIDENT_EPISODE),
939
+ ).toHaveLength(2);
940
+ expect(
941
+ rulesOfType(NotificationRuleType.ON_CALL_EXECUTED_ALERT_EPISODE),
942
+ ).toHaveLength(2);
943
+ });
944
+
945
+ test("the severity lookup is project-scoped, root-privileged and capped at LIMIT_PER_PROJECT", async () => {
946
+ stubSeverities([SEV_A], [ALERT_SEV_A]);
947
+
948
+ await runDefaults();
949
+
950
+ const incidentFindBy: jest.SpyInstance = jest.spyOn(
951
+ IncidentSeverityService,
952
+ "findBy",
953
+ );
954
+ const findArg: {
955
+ query: { projectId: ObjectID };
956
+ props: { isRoot: boolean };
957
+ limit: number;
958
+ skip: number;
959
+ } = incidentFindBy.mock.calls[0]![0] as {
960
+ query: { projectId: ObjectID };
961
+ props: { isRoot: boolean };
962
+ limit: number;
963
+ skip: number;
964
+ };
965
+
966
+ expect(findArg.query.projectId.toString()).toBe(PROJECT_ID.toString());
967
+ expect(findArg.props.isRoot).toBe(true);
968
+ expect(findArg.limit).toBe(LIMIT_PER_PROJECT);
969
+ expect(findArg.skip).toBe(0);
970
+ });
971
+
972
+ test("running twice against the same severities is idempotent - no duplicate rows", async () => {
973
+ stubSeverities([SEV_A, SEV_B], [ALERT_SEV_A, ALERT_SEV_B]);
974
+
975
+ await runDefaults();
976
+ const afterFirstRun: number = ruleStore.length;
977
+
978
+ await runDefaults();
979
+
980
+ expect(ruleStore).toHaveLength(afterFirstRun);
981
+ });
982
+
983
+ /*
984
+ * GAP A CLOSED - this behaviour is unchanged, and it is exactly WHY the
985
+ * backfill has to exist.
986
+ *
987
+ * Call one: severities [A, B]. A third severity C is then created in the
988
+ * project. Call two: severities [A, B, C] - and only NOW does the C rule
989
+ * appear. This method is still a snapshot of the moment it runs; what Phase 1
990
+ * added is something that makes call two happen, namely the backfill job that
991
+ * IncidentSeverityService.onCreateSuccess now enqueues.
992
+ */
993
+ test("a third severity only gets a rule because the method was called a SECOND time", async () => {
994
+ stubSeverities([SEV_A, SEV_B], []);
995
+ await runDefaults();
996
+
997
+ // Snapshot taken by call one: the user is covered for A and B only.
998
+ expect(incidentSeverityIdsCovered()).toEqual([
999
+ SEV_A.toString(),
1000
+ SEV_B.toString(),
1001
+ ]);
1002
+
1003
+ /*
1004
+ * "Sev4" is created here. In production creating it enqueues the backfill
1005
+ * job (see section (A)); this test stands in for that second pass by
1006
+ * re-running the defaults directly.
1007
+ */
1008
+ stubSeverities([SEV_A, SEV_B, SEV_C], []);
1009
+ await runDefaults();
1010
+
1011
+ expect(incidentSeverityIdsCovered()).toEqual([
1012
+ SEV_A.toString(),
1013
+ SEV_B.toString(),
1014
+ SEV_C.toString(),
1015
+ ]);
1016
+ });
1017
+
1018
+ test("the re-run adds exactly one row - the pre-existing severities are skipped", async () => {
1019
+ stubSeverities([SEV_A, SEV_B], []);
1020
+ await runDefaults();
1021
+ const afterFirstRun: number = ruleStore.length;
1022
+
1023
+ stubSeverities([SEV_A, SEV_B, SEV_C], []);
1024
+ await runDefaults();
1025
+
1026
+ /*
1027
+ * GAP G CLOSED - two rows, not one. A new incident severity now earns the
1028
+ * responder an ON_CALL_EXECUTED_INCIDENT rule AND an
1029
+ * ON_CALL_EXECUTED_INCIDENT_EPISODE rule, because episode rules are
1030
+ * severity-scoped now instead of a single severity-less row that could
1031
+ * never match.
1032
+ */
1033
+ expect(ruleStore.length - afterFirstRun).toBe(2);
1034
+ expect(
1035
+ rulesOfType(NotificationRuleType.ON_CALL_EXECUTED_INCIDENT),
1036
+ ).toHaveLength(3);
1037
+ });
1038
+
1039
+ /*
1040
+ * GAP A CLOSED - the alert half of the same snapshot property. Unchanged, and
1041
+ * likewise the reason AlertSeverityService now enqueues the backfill too.
1042
+ */
1043
+ test("a late alert severity is missed by this method the same way", async () => {
1044
+ stubSeverities([], [ALERT_SEV_A, ALERT_SEV_B]);
1045
+ await runDefaults();
1046
+
1047
+ expect(alertSeverityIdsCovered()).toEqual([
1048
+ ALERT_SEV_A.toString(),
1049
+ ALERT_SEV_B.toString(),
1050
+ ]);
1051
+
1052
+ // Severity C is created in the project. This method alone does no rule work.
1053
+ stubSeverities([], [ALERT_SEV_A, ALERT_SEV_B]);
1054
+
1055
+ expect(alertSeverityIdsCovered()).not.toContain(ALERT_SEV_C.toString());
1056
+ });
1057
+
1058
+ test("the existing-rule check is severity-specific, so a rule for A never satisfies C", async () => {
1059
+ stubSeverities([SEV_A], []);
1060
+ await runDefaults();
1061
+
1062
+ const findOneBySpy: jest.SpyInstance = jest.spyOn(
1063
+ UserNotificationRuleService,
1064
+ "findOneBy",
1065
+ );
1066
+
1067
+ const severityQueries: Array<Record<string, unknown>> =
1068
+ findOneBySpy.mock.calls
1069
+ .map((call: Array<unknown>): Record<string, unknown> => {
1070
+ return (call[0] as { query: Record<string, unknown> }).query;
1071
+ })
1072
+ .filter((query: Record<string, unknown>): boolean => {
1073
+ return (
1074
+ query["ruleType"] === NotificationRuleType.ON_CALL_EXECUTED_INCIDENT
1075
+ );
1076
+ });
1077
+
1078
+ expect(severityQueries).toHaveLength(1);
1079
+ expect(toIdString(severityQueries[0]!["incidentSeverityId"])).toBe(
1080
+ SEV_A.toString(),
1081
+ );
1082
+ });
1083
+ });
1084
+
1085
+ /*
1086
+ * ========================================================================= *
1087
+ * (C) The coverage hole, read through the query UserOnCallLogService really
1088
+ * issues: { userId, projectId, ruleType, incidentSeverityId }.
1089
+ *
1090
+ * The hole itself is unchanged - a user with rules for [A, B] still has no
1091
+ * row for C until the backfill job runs - but the consequence is not. Phase
1092
+ * 1 replaced the dead-end with the verified-method fallback, so the very
1093
+ * same C-severity incident now reaches the responder and the log records
1094
+ * which channel carried it.
1095
+ * =========================================================================
1096
+ */
1097
+
1098
+ describe("GAP A CLOSED - a severity added after the fact still pages, via the fallback", () => {
1099
+ let logUpdateSpy: jest.SpyInstance;
1100
+ let timelineUpdateSpy: jest.SpyInstance;
1101
+ let executeRuleSpy: jest.SpyInstance;
1102
+ let fallbackSpy: jest.SpyInstance;
1103
+
1104
+ beforeEach(async () => {
1105
+ stubUserNotificationRuleStore();
1106
+
1107
+ // The user joined when the project had severities A and B only.
1108
+ stubSeverities([SEV_A, SEV_B], [ALERT_SEV_A, ALERT_SEV_B]);
1109
+ await runDefaults();
1110
+
1111
+ logUpdateSpy = jest
1112
+ .spyOn(UserOnCallLogService, "updateOneById")
1113
+ .mockResolvedValue(1 as never);
1114
+ timelineUpdateSpy = jest
1115
+ .spyOn(OnCallDutyPolicyExecutionLogTimelineService, "updateOneById")
1116
+ .mockResolvedValue(1 as never);
1117
+ executeRuleSpy = jest
1118
+ .spyOn(UserNotificationRuleService, "executeNotificationRuleItem")
1119
+ .mockResolvedValue(undefined as never);
1120
+
1121
+ /*
1122
+ * The three collaborators the no-rule path reaches for now. The project read
1123
+ * decides whether the fallback is allowed at all (null => allowed, the
1124
+ * default), the fallback itself reports which channels it dispatched on, and
1125
+ * the user read only ever feeds a name into a failure message.
1126
+ */
1127
+ jest.spyOn(ProjectService, "findOneById").mockResolvedValue(null as never);
1128
+ jest.spyOn(UserService, "findOneById").mockResolvedValue(null as never);
1129
+ fallbackSpy = jest
1130
+ .spyOn(UserNotificationRuleService, "executeFallbackNotification")
1131
+ .mockResolvedValue({
1132
+ notified: true,
1133
+ channelsUsed: ["Email"],
1134
+ } as never);
1135
+ });
1136
+
1137
+ function stubIncident(incidentSeverityId: ObjectID): void {
1138
+ jest
1139
+ .spyOn(IncidentService, "findOneById")
1140
+ .mockImplementation(((): Promise<Incident> => {
1141
+ const incident: Incident = new Incident();
1142
+ incident._id = INCIDENT_ID.toString();
1143
+ incident.incidentSeverityId = incidentSeverityId;
1144
+
1145
+ return Promise.resolve(incident);
1146
+ }) as never);
1147
+ }
1148
+
1149
+ function stubAlert(alertSeverityId: ObjectID): void {
1150
+ jest
1151
+ .spyOn(AlertService, "findOneById")
1152
+ .mockImplementation(((): Promise<Alert> => {
1153
+ const alert: Alert = new Alert();
1154
+ alert._id = ALERT_ID.toString();
1155
+ alert.alertSeverityId = alertSeverityId;
1156
+
1157
+ return Promise.resolve(alert);
1158
+ }) as never);
1159
+ }
1160
+
1161
+ function incidentOnCallLog(): UserOnCallLog {
1162
+ const log: UserOnCallLog = new UserOnCallLog();
1163
+ log._id = LOG_ID.toString();
1164
+ log.projectId = PROJECT_ID;
1165
+ log.userId = USER_ID;
1166
+ log.triggeredByIncidentId = INCIDENT_ID;
1167
+ log.userNotificationEventType = UserNotificationEventType.IncidentCreated;
1168
+ log.onCallDutyPolicyExecutionLogTimelineId = TIMELINE_ID;
1169
+
1170
+ return log;
1171
+ }
1172
+
1173
+ function alertOnCallLog(): UserOnCallLog {
1174
+ const log: UserOnCallLog = new UserOnCallLog();
1175
+ log._id = LOG_ID.toString();
1176
+ log.projectId = PROJECT_ID;
1177
+ log.userId = USER_ID;
1178
+ log.triggeredByAlertId = ALERT_ID;
1179
+ log.userNotificationEventType = UserNotificationEventType.AlertCreated;
1180
+ log.onCallDutyPolicyExecutionLogTimelineId = TIMELINE_ID;
1181
+
1182
+ return log;
1183
+ }
1184
+
1185
+ function driveOnCreateSuccess(log: UserOnCallLog): Promise<unknown> {
1186
+ const onCreate: OnCreate<UserOnCallLog> = {
1187
+ createBy: {
1188
+ data: log,
1189
+ props: { isRoot: true },
1190
+ } as CreateBy<UserOnCallLog>,
1191
+ carryForward: null,
1192
+ };
1193
+
1194
+ return callHook(UserOnCallLogService, "onCreateSuccess", onCreate, log);
1195
+ }
1196
+
1197
+ function statusUpdates(): Array<{
1198
+ status: UserNotificationExecutionStatus;
1199
+ statusMessage?: string | undefined;
1200
+ }> {
1201
+ return logUpdateSpy.mock.calls.map(
1202
+ (
1203
+ call: Array<unknown>,
1204
+ ): {
1205
+ status: UserNotificationExecutionStatus;
1206
+ statusMessage?: string | undefined;
1207
+ } => {
1208
+ return (
1209
+ call[0] as {
1210
+ data: {
1211
+ status: UserNotificationExecutionStatus;
1212
+ statusMessage?: string | undefined;
1213
+ };
1214
+ }
1215
+ ).data;
1216
+ },
1217
+ );
1218
+ }
1219
+
1220
+ test("the runtime lookup keys on ruleType AND the incident's severity", async () => {
1221
+ stubIncident(SEV_C);
1222
+ const countBySpy: jest.SpyInstance = jest.spyOn(
1223
+ UserNotificationRuleService,
1224
+ "countBy",
1225
+ );
1226
+
1227
+ await driveOnCreateSuccess(incidentOnCallLog());
1228
+
1229
+ const query: Record<string, unknown> = (
1230
+ countBySpy.mock.calls[0]![0] as { query: Record<string, unknown> }
1231
+ ).query;
1232
+
1233
+ expect(toIdString(query["userId"])).toBe(USER_ID.toString());
1234
+ expect(toIdString(query["projectId"])).toBe(PROJECT_ID.toString());
1235
+ expect(query["ruleType"]).toBe(
1236
+ NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
1237
+ );
1238
+ expect(toIdString(query["incidentSeverityId"])).toBe(SEV_C.toString());
1239
+ });
1240
+
1241
+ /*
1242
+ * GAP A CLOSED - the count is still zero, and that is correct: the backfill
1243
+ * job has not run in this fixture. What changed is what a zero count now
1244
+ * causes, which the tests below assert. This one stays as the premise.
1245
+ */
1246
+ test("a user with rules for [A, B] has ZERO rules matching a C-severity incident", async () => {
1247
+ const count: PositiveNumber = await UserNotificationRuleService.countBy({
1248
+ query: {
1249
+ userId: USER_ID,
1250
+ projectId: PROJECT_ID,
1251
+ ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
1252
+ incidentSeverityId: SEV_C,
1253
+ },
1254
+ skip: 0,
1255
+ limit: LIMIT_PER_PROJECT,
1256
+ props: { isRoot: true },
1257
+ } as never);
1258
+
1259
+ expect(count.toNumber()).toBe(0);
1260
+ });
1261
+
1262
+ test("the same user does have a rule for the severities that existed when they joined", async () => {
1263
+ const countForA: PositiveNumber = await UserNotificationRuleService.countBy(
1264
+ {
1265
+ query: {
1266
+ userId: USER_ID,
1267
+ projectId: PROJECT_ID,
1268
+ ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
1269
+ incidentSeverityId: SEV_A,
1270
+ },
1271
+ skip: 0,
1272
+ limit: LIMIT_PER_PROJECT,
1273
+ props: { isRoot: true },
1274
+ } as never,
1275
+ );
1276
+
1277
+ expect(countForA.toNumber()).toBe(1);
1278
+ });
1279
+
1280
+ /*
1281
+ * GAP A CLOSED - the C-severity page is no longer dropped. No RULE is
1282
+ * executed, because there is still no rule to execute; the fallback is what
1283
+ * carries it, and it is handed the same severity name and rule type the count
1284
+ * came up empty for.
1285
+ */
1286
+ test("the C-severity page reaches the responder through the fallback", async () => {
1287
+ stubIncident(SEV_C);
1288
+
1289
+ await driveOnCreateSuccess(incidentOnCallLog());
1290
+
1291
+ expect(executeRuleSpy).not.toHaveBeenCalled();
1292
+ expect(fallbackSpy).toHaveBeenCalledTimes(1);
1293
+
1294
+ const options: Record<string, unknown> = fallbackSpy.mock
1295
+ .calls[0]![0] as Record<string, unknown>;
1296
+
1297
+ expect(toIdString(options["userId"])).toBe(USER_ID.toString());
1298
+ expect(toIdString(options["projectId"])).toBe(PROJECT_ID.toString());
1299
+ expect(options["ruleType"]).toBe(
1300
+ NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
1301
+ );
1302
+ });
1303
+
1304
+ /*
1305
+ * GAP A CLOSED - the inversion that matters most. The log used to end at
1306
+ * Error with a message nobody reads; it now ends at Executing with a message
1307
+ * that says a human was reached and on what.
1308
+ */
1309
+ test("the outcome is a fallback delivery, not a terminal Error", async () => {
1310
+ stubIncident(SEV_C);
1311
+
1312
+ await driveOnCreateSuccess(incidentOnCallLog());
1313
+
1314
+ const updates: Array<{
1315
+ status: UserNotificationExecutionStatus;
1316
+ statusMessage?: string | undefined;
1317
+ }> = statusUpdates();
1318
+
1319
+ // First update marks it Started, second records the fallback delivery.
1320
+ expect(updates[0]!.status).toBe(UserNotificationExecutionStatus.Started);
1321
+ expect(updates[1]!.status).toBe(UserNotificationExecutionStatus.Executing);
1322
+ expect(updates[1]!.statusMessage).toContain("notified via fallback");
1323
+ expect(updates[1]!.statusMessage).toContain("Email");
1324
+
1325
+ // The dead-end's sentence is gone from this path entirely.
1326
+ expect(
1327
+ updates.some(
1328
+ (update: { statusMessage?: string | undefined }): boolean => {
1329
+ return (
1330
+ update.statusMessage ===
1331
+ "No notification rules found for this user. User should add the rules in User Settings > On-Call Rules."
1332
+ );
1333
+ },
1334
+ ),
1335
+ ).toBe(false);
1336
+ expect(
1337
+ updates.some(
1338
+ (update: { status: UserNotificationExecutionStatus }): boolean => {
1339
+ return update.status === UserNotificationExecutionStatus.Error;
1340
+ },
1341
+ ),
1342
+ ).toBe(false);
1343
+ });
1344
+
1345
+ /*
1346
+ * GAP A CLOSED - the timeline now reads as a delivery rather than a failure,
1347
+ * and it names the channel. An operator reading the escalation can tell that
1348
+ * somebody was reached and how.
1349
+ */
1350
+ test("the on-call timeline shows a notification sent through the fallback", async () => {
1351
+ stubIncident(SEV_C);
1352
+
1353
+ await driveOnCreateSuccess(incidentOnCallLog());
1354
+
1355
+ expect(timelineUpdateSpy).toHaveBeenCalledTimes(1);
1356
+ const timelineArg: {
1357
+ id: ObjectID;
1358
+ data: {
1359
+ status: OnCallDutyExecutionLogTimelineStatus;
1360
+ statusMessage: string;
1361
+ };
1362
+ } = timelineUpdateSpy.mock.calls[0]![0] as {
1363
+ id: ObjectID;
1364
+ data: {
1365
+ status: OnCallDutyExecutionLogTimelineStatus;
1366
+ statusMessage: string;
1367
+ };
1368
+ };
1369
+
1370
+ expect(timelineArg.id.toString()).toBe(TIMELINE_ID.toString());
1371
+ expect(timelineArg.data.status).toBe(
1372
+ OnCallDutyExecutionLogTimelineStatus.NotificationSent,
1373
+ );
1374
+ expect(timelineArg.data.statusMessage).toContain("notified via fallback");
1375
+ expect(timelineArg.data.statusMessage).not.toContain(
1376
+ "No notification rules found for this user",
1377
+ );
1378
+ });
1379
+
1380
+ test("an incident on a severity that existed at join time pages the responder normally", async () => {
1381
+ stubIncident(SEV_A);
1382
+
1383
+ await driveOnCreateSuccess(incidentOnCallLog());
1384
+
1385
+ expect(executeRuleSpy).toHaveBeenCalledTimes(1);
1386
+
1387
+ const updates: Array<{ status: UserNotificationExecutionStatus }> =
1388
+ statusUpdates();
1389
+ expect(updates[updates.length - 1]!.status).toBe(
1390
+ UserNotificationExecutionStatus.Executing,
1391
+ );
1392
+ expect(timelineUpdateSpy).toHaveBeenCalledWith(
1393
+ expect.objectContaining({
1394
+ data: expect.objectContaining({
1395
+ status: OnCallDutyExecutionLogTimelineStatus.NotificationSent,
1396
+ }),
1397
+ }),
1398
+ );
1399
+ });
1400
+
1401
+ test("the immediate-rule lookup is severity-filtered too, so there is no accidental fallback", async () => {
1402
+ stubIncident(SEV_A);
1403
+ const findBySpy: jest.SpyInstance = jest.spyOn(
1404
+ UserNotificationRuleService,
1405
+ "findBy",
1406
+ );
1407
+
1408
+ await driveOnCreateSuccess(incidentOnCallLog());
1409
+
1410
+ const query: Record<string, unknown> = (
1411
+ findBySpy.mock.calls[0]![0] as { query: Record<string, unknown> }
1412
+ ).query;
1413
+
1414
+ expect(query["notifyAfterMinutes"]).toBe(0);
1415
+ expect(query["ruleType"]).toBe(
1416
+ NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
1417
+ );
1418
+ expect(toIdString(query["incidentSeverityId"])).toBe(SEV_A.toString());
1419
+ expect(query["alertSeverityId"]).toBeUndefined();
1420
+ });
1421
+
1422
+ /*
1423
+ * GAP A CLOSED - alerts take the same route as incidents. The rule type
1424
+ * handed to the fallback is the ALERT one, so whatever the fallback decides is
1425
+ * decided against the right cell.
1426
+ */
1427
+ test("an ALERT on a severity added after the fact is rescued the same way", async () => {
1428
+ stubAlert(ALERT_SEV_C);
1429
+
1430
+ await driveOnCreateSuccess(alertOnCallLog());
1431
+
1432
+ expect(executeRuleSpy).not.toHaveBeenCalled();
1433
+ expect(fallbackSpy).toHaveBeenCalledTimes(1);
1434
+ expect(
1435
+ (fallbackSpy.mock.calls[0]![0] as Record<string, unknown>)["ruleType"],
1436
+ ).toBe(NotificationRuleType.ON_CALL_EXECUTED_ALERT);
1437
+
1438
+ const updates: Array<{
1439
+ status: UserNotificationExecutionStatus;
1440
+ statusMessage?: string | undefined;
1441
+ }> = statusUpdates();
1442
+ expect(updates[1]!.status).toBe(UserNotificationExecutionStatus.Executing);
1443
+ expect(updates[1]!.statusMessage).toContain("notified via fallback");
1444
+ });
1445
+
1446
+ /*
1447
+ * GAP A CLOSED - and the other side of it. A responder with no verified
1448
+ * method at all cannot be rescued by anything, and that is the one case that
1449
+ * must still end as a loud, terminal Error naming what to do about it.
1450
+ */
1451
+ test("a responder with no verified method still ends as an explicit Error", async () => {
1452
+ stubIncident(SEV_C);
1453
+ fallbackSpy.mockResolvedValue({
1454
+ notified: false,
1455
+ outcome: FallbackNotificationOutcome.NoUsableNotificationMethod,
1456
+ channelsUsed: [],
1457
+ } as never);
1458
+
1459
+ await driveOnCreateSuccess(incidentOnCallLog());
1460
+
1461
+ const updates: Array<{
1462
+ status: UserNotificationExecutionStatus;
1463
+ statusMessage?: string | undefined;
1464
+ }> = statusUpdates();
1465
+
1466
+ expect(updates[1]!.status).toBe(UserNotificationExecutionStatus.Error);
1467
+ expect(updates[1]!.statusMessage).toContain(
1468
+ "has no verified notification method",
1469
+ );
1470
+ expect(updates[1]!.statusMessage).toContain(
1471
+ "User Settings > Notification Methods",
1472
+ );
1473
+ });
1474
+
1475
+ test("an alert on a severity that existed at join time still pages", async () => {
1476
+ stubAlert(ALERT_SEV_A);
1477
+
1478
+ await driveOnCreateSuccess(alertOnCallLog());
1479
+
1480
+ expect(executeRuleSpy).toHaveBeenCalledTimes(1);
1481
+ });
1482
+
1483
+ /*
1484
+ * The two Phase 1 halves are independent, and this is the proof: with the row
1485
+ * present the responder is paged through their OWN configured rule and the
1486
+ * fallback is never consulted at all. The backfill is what restores the
1487
+ * responder's intent; the fallback is only the safety net under it.
1488
+ */
1489
+ test("backfilling the missing row is sufficient: the very same C-severity incident pages through the real rule", async () => {
1490
+ stubIncident(SEV_C);
1491
+
1492
+ // Re-running the defaults against a project that now has C is the backfill.
1493
+ stubSeverities([SEV_A, SEV_B, SEV_C], [ALERT_SEV_A, ALERT_SEV_B]);
1494
+ await runDefaults();
1495
+
1496
+ await driveOnCreateSuccess(incidentOnCallLog());
1497
+
1498
+ expect(executeRuleSpy).toHaveBeenCalledTimes(1);
1499
+ expect(fallbackSpy).not.toHaveBeenCalled();
1500
+
1501
+ const updates: Array<{ status: UserNotificationExecutionStatus }> =
1502
+ statusUpdates();
1503
+ expect(updates[updates.length - 1]!.status).toBe(
1504
+ UserNotificationExecutionStatus.Executing,
1505
+ );
1506
+ });
1507
+
1508
+ test("without the backfill the store simply has no row for the new severity", async () => {
1509
+ const rowsForC: Array<StoredRule> = matchingRules({
1510
+ userId: USER_ID,
1511
+ projectId: PROJECT_ID,
1512
+ ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
1513
+ incidentSeverityId: SEV_C,
1514
+ });
1515
+
1516
+ expect(rowsForC).toHaveLength(0);
1517
+
1518
+ // ... while the severities present at join time each have exactly one.
1519
+ expect(
1520
+ matchingRules({
1521
+ userId: USER_ID,
1522
+ projectId: PROJECT_ID,
1523
+ ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
1524
+ incidentSeverityId: SEV_A,
1525
+ }),
1526
+ ).toHaveLength(1);
1527
+ expect(
1528
+ matchingRules({
1529
+ userId: USER_ID,
1530
+ projectId: PROJECT_ID,
1531
+ ruleType: NotificationRuleType.ON_CALL_EXECUTED_INCIDENT,
1532
+ incidentSeverityId: SEV_B,
1533
+ }),
1534
+ ).toHaveLength(1);
1535
+ });
1536
+ });