@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,1393 @@
1
+ import UserNotificationRuleService from "../../../Server/Services/UserNotificationRuleService";
2
+ import UserOnCallLogService from "../../../Server/Services/UserOnCallLogService";
3
+ import UserOnCallLogTimelineService from "../../../Server/Services/UserOnCallLogTimelineService";
4
+ import ProjectCallSMSConfigService from "../../../Server/Services/ProjectCallSMSConfigService";
5
+ import IncidentService from "../../../Server/Services/IncidentService";
6
+ import AlertService from "../../../Server/Services/AlertService";
7
+ import AlertEpisodeService from "../../../Server/Services/AlertEpisodeService";
8
+ import IncidentEpisodeService from "../../../Server/Services/IncidentEpisodeService";
9
+ import MailService from "../../../Server/Services/MailService";
10
+ import SmsService from "../../../Server/Services/SmsService";
11
+ import CallService from "../../../Server/Services/CallService";
12
+ import WhatsAppService from "../../../Server/Services/WhatsAppService";
13
+ import TelegramService from "../../../Server/Services/TelegramService";
14
+ import WebhookService from "../../../Server/Services/WebhookService";
15
+ import PushNotificationService from "../../../Server/Services/PushNotificationService";
16
+ import logger from "../../../Server/Utils/Logger";
17
+ import Incident from "../../../Models/DatabaseModels/Incident";
18
+ import UserOnCallLogTimeline from "../../../Models/DatabaseModels/UserOnCallLogTimeline";
19
+ import UserNotificationRule from "../../../Models/DatabaseModels/UserNotificationRule";
20
+ import UserEmail from "../../../Models/DatabaseModels/UserEmail";
21
+ import UserPush from "../../../Models/DatabaseModels/UserPush";
22
+ import UserSMS from "../../../Models/DatabaseModels/UserSMS";
23
+ import BadDataException from "../../../Types/Exception/BadDataException";
24
+ import Email from "../../../Types/Email";
25
+ import Phone from "../../../Types/Phone";
26
+ import ObjectID from "../../../Types/ObjectID";
27
+ import URL from "../../../Types/API/URL";
28
+ import { JSONObject } from "../../../Types/JSON";
29
+ import EmailMessage from "../../../Types/Email/EmailMessage";
30
+ import SMS from "../../../Types/SMS/SMS";
31
+ import TwilioConfig from "../../../Types/CallAndSMS/TwilioConfig";
32
+ import NotificationRuleType from "../../../Types/NotificationRule/NotificationRuleType";
33
+ import PushDeviceType from "../../../Types/PushNotification/PushDeviceType";
34
+ import UserNotificationEventType from "../../../Types/UserNotification/UserNotificationEventType";
35
+ import UserNotificationStatus from "../../../Types/UserNotification/UserNotificationStatus";
36
+ import { describe, expect, test, beforeEach, afterEach } from "@jest/globals";
37
+
38
+ /*
39
+ * Phase 1 §2.1 split `executeNotificationRuleItem` in two. The public method
40
+ * kept its signature and now does only what a rule ID implies — claim the
41
+ * on-call log, load the rule, hand both to the delivery half — and everything
42
+ * from the Twilio-config lookup downwards moved into a private
43
+ * `deliverNotificationForRule(rule, options)`.
44
+ *
45
+ * The extraction exists so the on-call FALLBACK can reuse the delivery half
46
+ * with a UserNotificationRule it assembled in memory and never saved: there is
47
+ * no rule row to claim and no id to look up, so the first half is meaningless
48
+ * to it while the second half is exactly what it needs. That makes the SEAM
49
+ * between the two halves — not the seven channel blocks, which
50
+ * NotificationChannelEventCoverage.test.ts owns — the thing worth pinning, and
51
+ * this file pins five properties of it:
52
+ *
53
+ * 1. THE CLAIM IS STILL FIRST. The atomic claim (audit F7) is what stops two
54
+ * overlapping cron ticks double-paging one responder. A refactor that let
55
+ * the rule load drift above it, or that read `false` as "carry on", brings
56
+ * duplicate pages straight back — so a lost claim is asserted to stop the
57
+ * method before `findOneById` is even called, not merely before the send.
58
+ *
59
+ * 2. A MISSING RULE STILL THROWS. `BadDataException("Notification rule item
60
+ * not found.")` is what ExecutePendingExecutions turns into an `Error`
61
+ * log. Swallowing it during the split would leave the log stuck Executing
62
+ * forever.
63
+ *
64
+ * 3. THE SELECT SURVIVED INTACT. Every channel gate reads
65
+ * `<method>?.isVerified`, and an unselected column arrives as `undefined`.
66
+ * Dropping `isVerified` from this select therefore does NOT page
67
+ * unverified methods — it silences every VERIFIED one and writes "not
68
+ * verified" rows about perfectly verified phones. `userWebhook`'s
69
+ * `webhookUrl`/`name`/`secret` matter for the opposite reason: `secret`
70
+ * signs the outgoing request. The shape is asserted field by field.
71
+ *
72
+ * 4. THE RULE CROSSES THE SEAM UNCHANGED. The object `findOneById` returned
73
+ * and the caller's own options bag are handed to the delivery half by
74
+ * reference — no copy, no reshaping, nothing dropped on the way.
75
+ *
76
+ * 5. THE DELIVERY HALF STANDS ALONE. It can be driven directly with an
77
+ * UNSAVED, id-less rule and still writes a timeline row and dispatches.
78
+ * This is the regression guard for blocker B1: while
79
+ * `UserOnCallLogTimeline.userNotificationRuleId` was NOT NULL, every
80
+ * fallback delivery threw at the first `create()` — before a single page
81
+ * left the process — because an unsaved rule has no id to put there.
82
+ *
83
+ * Plus the one value the split had to keep hoisted: `projectTwilioConfig` is
84
+ * resolved ONCE, inside the delivery half, from `options.projectId`, and handed
85
+ * to the paid senders. Resolving it per channel would multiply a project-config
86
+ * read by the number of channels; resolving it in the public half would leave
87
+ * the fallback sending on the GLOBAL Twilio account.
88
+ *
89
+ * No database is touched. Every sender, every template generator and every
90
+ * persistence call is a `jest.spyOn` stub, and the private delivery half is
91
+ * reached through a cast, exactly as the neighbouring characterisation tests
92
+ * reach protected hooks.
93
+ */
94
+
95
+ const PROJECT_ID: ObjectID = new ObjectID(
96
+ "11111111-1111-4111-8111-111111111111",
97
+ );
98
+ const RULE_ID: ObjectID = new ObjectID("22222222-2222-4222-8222-222222222222");
99
+ const LOG_ID: ObjectID = new ObjectID("33333333-3333-4333-8333-333333333333");
100
+ const USER_ID: ObjectID = new ObjectID("44444444-4444-4444-8444-444444444444");
101
+ const INCIDENT_ID: ObjectID = new ObjectID(
102
+ "55555555-5555-4555-8555-555555555555",
103
+ );
104
+ const TEAM_ID: ObjectID = new ObjectID("66666666-6666-4666-8666-666666666666");
105
+ const POLICY_ID: ObjectID = new ObjectID(
106
+ "77777777-7777-4777-8777-777777777777",
107
+ );
108
+ const ESCALATION_RULE_ID: ObjectID = new ObjectID(
109
+ "88888888-8888-4888-8888-888888888888",
110
+ );
111
+ const EXECUTION_LOG_TIMELINE_ID: ObjectID = new ObjectID(
112
+ "99999999-9999-4999-8999-999999999999",
113
+ );
114
+ const TIMELINE_ID: ObjectID = new ObjectID(
115
+ "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
116
+ );
117
+ const EMAIL_METHOD_ID: ObjectID = new ObjectID(
118
+ "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
119
+ );
120
+ const SMS_METHOD_ID: ObjectID = new ObjectID(
121
+ "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
122
+ );
123
+ const PUSH_METHOD_ID: ObjectID = new ObjectID(
124
+ "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
125
+ );
126
+
127
+ const RESPONDER_EMAIL: string = "responder@company.com";
128
+ const RESPONDER_PHONE: string = "+11234567890";
129
+
130
+ /* The options bag both halves share, taken from the public signature. */
131
+ type ExecuteOptions = Parameters<
132
+ typeof UserNotificationRuleService.executeNotificationRuleItem
133
+ >[1];
134
+
135
+ /* The `select` / `props` bundle handed to findOneById. */
136
+ interface FindOneByIdArg {
137
+ id: ObjectID;
138
+ select: JSONObject;
139
+ props: { isRoot: boolean };
140
+ }
141
+
142
+ /*
143
+ * `deliverNotificationForRule` is private, so TypeScript will not let a test
144
+ * name it on the service. It is a perfectly ordinary prototype method at
145
+ * runtime, and the fallback's whole design rests on it being callable with a
146
+ * rule that was never persisted — so it is reached here through a structural
147
+ * cast, the same trick the neighbouring files use for protected hooks.
148
+ *
149
+ * It returns whether a page was actually handed to a sender. That boolean is
150
+ * NOT decoration: executeFallbackNotification reads it to decide which channel
151
+ * names to tell the operator the responder was reached on.
152
+ */
153
+ interface DeliveryHalf {
154
+ deliverNotificationForRule: (
155
+ notificationRuleItem: UserNotificationRule,
156
+ options: ExecuteOptions,
157
+ ) => Promise<boolean>;
158
+ }
159
+
160
+ function deliveryHalf(): DeliveryHalf {
161
+ return UserNotificationRuleService as unknown as DeliveryHalf;
162
+ }
163
+
164
+ /*
165
+ * The service mutates ONE UserOnCallLogTimeline instance per delivery call and
166
+ * hands that same instance to create(), so mock.calls all alias its final
167
+ * state. Snapshot the fields at call time instead; the raw instances are kept
168
+ * separately, because "did two delivery calls build two distinct rows" is a
169
+ * question only identity can answer.
170
+ */
171
+ interface TimelineRow {
172
+ status: UserNotificationStatus | undefined;
173
+ statusMessage: string | undefined;
174
+ userId: ObjectID | undefined;
175
+ userNotificationRuleId: ObjectID | undefined;
176
+ userNotificationLogId: ObjectID | undefined;
177
+ projectId: ObjectID | undefined;
178
+ userNotificationEventType: UserNotificationEventType | undefined;
179
+ userEmailId: ObjectID | undefined;
180
+ userSmsId: ObjectID | undefined;
181
+ userPushId: ObjectID | undefined;
182
+ triggeredByIncidentId: ObjectID | undefined;
183
+ onCallDutyPolicyId: ObjectID | undefined;
184
+ onCallDutyPolicyEscalationRuleId: ObjectID | undefined;
185
+ userBelongsToTeamId: ObjectID | undefined;
186
+ }
187
+
188
+ function executeOptions(
189
+ overrides: Partial<ExecuteOptions> = {},
190
+ ): ExecuteOptions {
191
+ return {
192
+ projectId: PROJECT_ID,
193
+ userNotificationEventType: UserNotificationEventType.IncidentCreated,
194
+ triggeredByIncidentId: INCIDENT_ID,
195
+ onCallPolicyId: POLICY_ID,
196
+ onCallPolicyEscalationRuleId: ESCALATION_RULE_ID,
197
+ userBelongsToTeamId: TEAM_ID,
198
+ onCallDutyPolicyExecutionLogTimelineId: EXECUTION_LOG_TIMELINE_ID,
199
+ userNotificationLogId: LOG_ID,
200
+ ...overrides,
201
+ };
202
+ }
203
+
204
+ /*
205
+ * A rule as findOneById hands it back: hydrated, and carrying the `_id` of the
206
+ * row it was read from.
207
+ */
208
+ function loadedRule(channels: JSONObject = {}): UserNotificationRule {
209
+ return {
210
+ id: RULE_ID,
211
+ _id: RULE_ID.toString(),
212
+ userId: USER_ID,
213
+ ...channels,
214
+ } as unknown as UserNotificationRule;
215
+ }
216
+
217
+ /*
218
+ * A rule as the FALLBACK builds it: a real model instance with no `_id`, so
219
+ * `.id` is genuinely null, assembled from the user's verified methods and
220
+ * never saved. Real model classes are used rather than object literals
221
+ * precisely because `id` is a getter over `_id` — a literal would fake the one
222
+ * property this half of the file is about.
223
+ */
224
+ function unsavedFallbackRule(): UserNotificationRule {
225
+ const rule: UserNotificationRule = new UserNotificationRule();
226
+ rule.projectId = PROJECT_ID;
227
+ rule.userId = USER_ID;
228
+ rule.ruleType = NotificationRuleType.ON_CALL_EXECUTED_INCIDENT;
229
+ rule.notifyAfterMinutes = 0;
230
+
231
+ return rule;
232
+ }
233
+
234
+ function verifiedUserEmail(): UserEmail {
235
+ const userEmail: UserEmail = new UserEmail();
236
+ userEmail._id = EMAIL_METHOD_ID.toString();
237
+ userEmail.email = new Email(RESPONDER_EMAIL);
238
+ userEmail.isVerified = true;
239
+
240
+ return userEmail;
241
+ }
242
+
243
+ function verifiedUserSms(): UserSMS {
244
+ const userSms: UserSMS = new UserSMS();
245
+ userSms._id = SMS_METHOD_ID.toString();
246
+ userSms.phone = new Phone(RESPONDER_PHONE);
247
+ userSms.isVerified = true;
248
+
249
+ return userSms;
250
+ }
251
+
252
+ function verifiedUserPush(): UserPush {
253
+ const userPush: UserPush = new UserPush();
254
+ userPush._id = PUSH_METHOD_ID.toString();
255
+ userPush.deviceToken = "device-token";
256
+ userPush.deviceType = PushDeviceType.iOS;
257
+ userPush.isVerified = true;
258
+
259
+ return userPush;
260
+ }
261
+
262
+ function fakeIncident(): Incident {
263
+ return {
264
+ id: INCIDENT_ID,
265
+ projectId: PROJECT_ID,
266
+ title: "Checkout is down",
267
+ description: "Checkout returns 500 for every request.",
268
+ incidentNumber: 42,
269
+ incidentNumberWithPrefix: "INC-42",
270
+ } as unknown as Incident;
271
+ }
272
+
273
+ function fakeTwilioConfig(): TwilioConfig {
274
+ return {
275
+ accountSid: "AC-project-account",
276
+ authToken: "project-auth-token",
277
+ primaryPhoneNumber: new Phone("+15550001111"),
278
+ secondaryPhoneNumbers: [],
279
+ };
280
+ }
281
+
282
+ /* Every stub the two halves touch, so no test can reach a real service. */
283
+ interface Spies {
284
+ claim: jest.SpyInstance;
285
+ findRule: jest.SpyInstance;
286
+ createRule: jest.SpyInstance;
287
+ twilio: jest.SpyInstance;
288
+ timelineCreate: jest.SpyInstance;
289
+ timelineUpdate: jest.SpyInstance;
290
+ incidentFind: jest.SpyInstance;
291
+ incidentLink: jest.SpyInstance;
292
+ alertFind: jest.SpyInstance;
293
+ alertEpisodeFind: jest.SpyInstance;
294
+ incidentEpisodeFind: jest.SpyInstance;
295
+ mail: jest.SpyInstance;
296
+ sms: jest.SpyInstance;
297
+ call: jest.SpyInstance;
298
+ whatsApp: jest.SpyInstance;
299
+ telegram: jest.SpyInstance;
300
+ webhook: jest.SpyInstance;
301
+ push: jest.SpyInstance;
302
+ emailTemplate: jest.SpyInstance;
303
+ smsTemplate: jest.SpyInstance;
304
+ }
305
+
306
+ describe("UserNotificationRuleService - the deliverNotificationForRule extraction", () => {
307
+ let spies: Spies;
308
+ let timelineRows: Array<TimelineRow>;
309
+ let timelineInstances: Array<UserOnCallLogTimeline>;
310
+
311
+ beforeEach(() => {
312
+ timelineRows = [];
313
+ timelineInstances = [];
314
+
315
+ jest.spyOn(logger, "error").mockImplementation((): void => {
316
+ return undefined;
317
+ });
318
+ jest.spyOn(logger, "warn").mockImplementation((): void => {
319
+ return undefined;
320
+ });
321
+
322
+ const timelineCreate: jest.SpyInstance = jest.spyOn(
323
+ UserOnCallLogTimelineService,
324
+ "create",
325
+ );
326
+ timelineCreate.mockImplementation(
327
+ (createBy: unknown): Promise<UserOnCallLogTimeline> => {
328
+ const data: UserOnCallLogTimeline = (
329
+ createBy as { data: UserOnCallLogTimeline }
330
+ ).data;
331
+
332
+ timelineInstances.push(data);
333
+ timelineRows.push({
334
+ status: data.status,
335
+ statusMessage: data.statusMessage,
336
+ userId: data.userId,
337
+ userNotificationRuleId: data.userNotificationRuleId,
338
+ userNotificationLogId: data.userNotificationLogId,
339
+ projectId: data.projectId,
340
+ userNotificationEventType: data.userNotificationEventType,
341
+ userEmailId: data.userEmailId,
342
+ userSmsId: data.userSmsId,
343
+ userPushId: data.userPushId,
344
+ triggeredByIncidentId: data.triggeredByIncidentId,
345
+ onCallDutyPolicyId: data.onCallDutyPolicyId,
346
+ onCallDutyPolicyEscalationRuleId:
347
+ data.onCallDutyPolicyEscalationRuleId,
348
+ userBelongsToTeamId: data.userBelongsToTeamId,
349
+ });
350
+
351
+ return Promise.resolve({
352
+ id: TIMELINE_ID,
353
+ } as unknown as UserOnCallLogTimeline);
354
+ },
355
+ );
356
+
357
+ spies = {
358
+ claim: jest
359
+ .spyOn(UserOnCallLogService, "claimNotificationRuleExecution")
360
+ .mockResolvedValue(true as never),
361
+ findRule: jest
362
+ .spyOn(UserNotificationRuleService, "findOneById")
363
+ .mockResolvedValue(loadedRule() as never),
364
+ createRule: jest
365
+ .spyOn(UserNotificationRuleService, "create")
366
+ .mockResolvedValue(loadedRule() as never),
367
+ twilio: jest
368
+ .spyOn(ProjectCallSMSConfigService, "getProjectDefaultTwilioConfig")
369
+ .mockResolvedValue(undefined as never),
370
+ timelineCreate: timelineCreate,
371
+ timelineUpdate: jest
372
+ .spyOn(UserOnCallLogTimelineService, "updateOneById")
373
+ .mockResolvedValue(undefined as never),
374
+ incidentFind: jest
375
+ .spyOn(IncidentService, "findOneById")
376
+ .mockResolvedValue(fakeIncident() as never),
377
+ incidentLink: jest
378
+ .spyOn(IncidentService, "getIncidentLinkInDashboard")
379
+ .mockResolvedValue(
380
+ URL.fromString("https://dashboard.example.com/incident") as never,
381
+ ),
382
+ alertFind: jest
383
+ .spyOn(AlertService, "findOneById")
384
+ .mockResolvedValue(null as never),
385
+ alertEpisodeFind: jest
386
+ .spyOn(AlertEpisodeService, "findOneById")
387
+ .mockResolvedValue(null as never),
388
+ incidentEpisodeFind: jest
389
+ .spyOn(IncidentEpisodeService, "findOneById")
390
+ .mockResolvedValue(null as never),
391
+ mail: jest
392
+ .spyOn(MailService, "sendMail")
393
+ .mockResolvedValue(undefined as never),
394
+ sms: jest
395
+ .spyOn(SmsService, "sendSms")
396
+ .mockResolvedValue(undefined as never),
397
+ call: jest
398
+ .spyOn(CallService, "makeCall")
399
+ .mockResolvedValue(undefined as never),
400
+ whatsApp: jest
401
+ .spyOn(WhatsAppService, "sendWhatsAppMessage")
402
+ .mockResolvedValue(undefined as never),
403
+ telegram: jest
404
+ .spyOn(TelegramService, "sendTelegramMessage")
405
+ .mockResolvedValue(undefined as never),
406
+ webhook: jest
407
+ .spyOn(WebhookService, "sendWebhook")
408
+ .mockResolvedValue(undefined as never),
409
+ push: jest
410
+ .spyOn(PushNotificationService, "sendPushNotification")
411
+ .mockResolvedValue(undefined as never),
412
+ emailTemplate: jest
413
+ .spyOn(
414
+ UserNotificationRuleService,
415
+ "generateEmailTemplateForIncidentCreated",
416
+ )
417
+ .mockResolvedValue({} as EmailMessage as never),
418
+ smsTemplate: jest
419
+ .spyOn(
420
+ UserNotificationRuleService,
421
+ "generateSmsTemplateForIncidentCreated",
422
+ )
423
+ .mockResolvedValue({} as SMS as never),
424
+ };
425
+ });
426
+
427
+ afterEach(() => {
428
+ jest.restoreAllMocks();
429
+ });
430
+
431
+ function everySender(): Array<jest.SpyInstance> {
432
+ return [
433
+ spies.mail,
434
+ spies.sms,
435
+ spies.call,
436
+ spies.whatsApp,
437
+ spies.telegram,
438
+ spies.webhook,
439
+ spies.push,
440
+ ];
441
+ }
442
+
443
+ /*
444
+ * Replace the delivery half so the public half can be observed on its own.
445
+ * Installed per test rather than in beforeEach, because the sections below
446
+ * that drive the delivery half directly need the REAL implementation.
447
+ */
448
+ function stubDeliveryHalf(): jest.SpyInstance {
449
+ return jest
450
+ .spyOn(deliveryHalf(), "deliverNotificationForRule")
451
+ .mockResolvedValue(true as never);
452
+ }
453
+
454
+ /* The second argument SmsService.sendSms was handed. */
455
+ function sentSmsOptions(): {
456
+ customTwilioConfig: TwilioConfig | undefined;
457
+ } {
458
+ return spies.sms.mock.calls[0]![1] as {
459
+ customTwilioConfig: TwilioConfig | undefined;
460
+ };
461
+ }
462
+
463
+ /*
464
+ * ----------------------------------------------------------------------- *
465
+ * (A) The claim still runs, and still runs FIRST.
466
+ * -----------------------------------------------------------------------
467
+ */
468
+
469
+ describe("the public half still claims before it loads anything", () => {
470
+ test("a lost claim returns before findOneById is called at all", async () => {
471
+ spies.claim.mockResolvedValue(false as never);
472
+
473
+ await UserNotificationRuleService.executeNotificationRuleItem(
474
+ RULE_ID,
475
+ executeOptions(),
476
+ );
477
+
478
+ expect(spies.claim).toHaveBeenCalledTimes(1);
479
+ /*
480
+ * The point of F7. Short-circuiting merely before the SEND would still
481
+ * let two ticks race on the read; the gate has to be above the read.
482
+ */
483
+ expect(spies.findRule).not.toHaveBeenCalled();
484
+ });
485
+
486
+ test("a lost claim never reaches the delivery half", async () => {
487
+ const deliver: jest.SpyInstance = stubDeliveryHalf();
488
+ spies.claim.mockResolvedValue(false as never);
489
+
490
+ await UserNotificationRuleService.executeNotificationRuleItem(
491
+ RULE_ID,
492
+ executeOptions(),
493
+ );
494
+
495
+ expect(deliver).not.toHaveBeenCalled();
496
+ });
497
+
498
+ test("a lost claim sends nothing and writes no timeline row", async () => {
499
+ spies.claim.mockResolvedValue(false as never);
500
+ spies.findRule.mockResolvedValue(
501
+ loadedRule({
502
+ userEmail: verifiedUserEmail(),
503
+ } as unknown as JSONObject) as never,
504
+ );
505
+
506
+ await UserNotificationRuleService.executeNotificationRuleItem(
507
+ RULE_ID,
508
+ executeOptions(),
509
+ );
510
+
511
+ for (const sender of everySender()) {
512
+ expect(sender).not.toHaveBeenCalled();
513
+ }
514
+ expect(spies.timelineCreate).not.toHaveBeenCalled();
515
+ expect(spies.timelineUpdate).not.toHaveBeenCalled();
516
+ });
517
+
518
+ test("a lost claim skips the Twilio config and the incident lookup too", async () => {
519
+ spies.claim.mockResolvedValue(false as never);
520
+
521
+ await UserNotificationRuleService.executeNotificationRuleItem(
522
+ RULE_ID,
523
+ executeOptions(),
524
+ );
525
+
526
+ expect(spies.twilio).not.toHaveBeenCalled();
527
+ expect(spies.incidentFind).not.toHaveBeenCalled();
528
+ });
529
+
530
+ test("a lost claim RESOLVES - it is a normal outcome, not bad data", async () => {
531
+ spies.claim.mockResolvedValue(false as never);
532
+
533
+ /*
534
+ * ExecutePendingExecutions marks a log Error on BadDataException. A
535
+ * duplicate suppressed by the claim is not an error, so this path must
536
+ * resolve quietly or every suppressed duplicate burns its on-call log.
537
+ */
538
+ await expect(
539
+ UserNotificationRuleService.executeNotificationRuleItem(
540
+ RULE_ID,
541
+ executeOptions(),
542
+ ),
543
+ ).resolves.toBeUndefined();
544
+ });
545
+
546
+ test("the claim names this on-call log and this rule", async () => {
547
+ spies.claim.mockResolvedValue(false as never);
548
+
549
+ await UserNotificationRuleService.executeNotificationRuleItem(
550
+ RULE_ID,
551
+ executeOptions({ userNotificationLogId: LOG_ID }),
552
+ );
553
+
554
+ const claimArg: {
555
+ userOnCallLogId: ObjectID;
556
+ userNotificationRuleId: ObjectID;
557
+ } = spies.claim.mock.calls[0]![0] as {
558
+ userOnCallLogId: ObjectID;
559
+ userNotificationRuleId: ObjectID;
560
+ };
561
+ expect(claimArg.userOnCallLogId.toString()).toBe(LOG_ID.toString());
562
+ expect(claimArg.userNotificationRuleId.toString()).toBe(
563
+ RULE_ID.toString(),
564
+ );
565
+ });
566
+
567
+ test("the claim strictly PRECEDES the rule load, which precedes the delivery half", async () => {
568
+ const deliver: jest.SpyInstance = stubDeliveryHalf();
569
+
570
+ await UserNotificationRuleService.executeNotificationRuleItem(
571
+ RULE_ID,
572
+ executeOptions(),
573
+ );
574
+
575
+ expect(spies.claim.mock.invocationCallOrder[0]).toBeLessThan(
576
+ spies.findRule.mock.invocationCallOrder[0] as number,
577
+ );
578
+ expect(spies.findRule.mock.invocationCallOrder[0]).toBeLessThan(
579
+ deliver.mock.invocationCallOrder[0] as number,
580
+ );
581
+ });
582
+
583
+ test("a claim that rejects propagates and nothing is loaded or delivered", async () => {
584
+ const deliver: jest.SpyInstance = stubDeliveryHalf();
585
+ spies.claim.mockRejectedValue(new Error("db connection reset") as never);
586
+
587
+ await expect(
588
+ UserNotificationRuleService.executeNotificationRuleItem(
589
+ RULE_ID,
590
+ executeOptions(),
591
+ ),
592
+ ).rejects.toThrow("db connection reset");
593
+
594
+ expect(spies.findRule).not.toHaveBeenCalled();
595
+ expect(deliver).not.toHaveBeenCalled();
596
+ });
597
+
598
+ test("a held claim lets execution proceed, and the rule is read exactly once", async () => {
599
+ stubDeliveryHalf();
600
+
601
+ await UserNotificationRuleService.executeNotificationRuleItem(
602
+ RULE_ID,
603
+ executeOptions(),
604
+ );
605
+
606
+ expect(spies.claim).toHaveBeenCalledTimes(1);
607
+ expect(spies.findRule).toHaveBeenCalledTimes(1);
608
+ });
609
+ });
610
+
611
+ /*
612
+ * ----------------------------------------------------------------------- *
613
+ * (B) A rule id that resolves to nothing.
614
+ * -----------------------------------------------------------------------
615
+ */
616
+
617
+ describe("a rule id that resolves to nothing", () => {
618
+ test('still throws BadDataException("Notification rule item not found.")', async () => {
619
+ spies.findRule.mockResolvedValue(null as never);
620
+
621
+ await expect(
622
+ UserNotificationRuleService.executeNotificationRuleItem(
623
+ RULE_ID,
624
+ executeOptions(),
625
+ ),
626
+ ).rejects.toThrow(BadDataException);
627
+
628
+ await expect(
629
+ UserNotificationRuleService.executeNotificationRuleItem(
630
+ RULE_ID,
631
+ executeOptions(),
632
+ ),
633
+ ).rejects.toThrow("Notification rule item not found.");
634
+ });
635
+
636
+ test("the delivery half is never entered on a missing rule", async () => {
637
+ const deliver: jest.SpyInstance = stubDeliveryHalf();
638
+ spies.findRule.mockResolvedValue(null as never);
639
+
640
+ await expect(
641
+ UserNotificationRuleService.executeNotificationRuleItem(
642
+ RULE_ID,
643
+ executeOptions(),
644
+ ),
645
+ ).rejects.toThrow(BadDataException);
646
+
647
+ expect(deliver).not.toHaveBeenCalled();
648
+ });
649
+
650
+ test("the throw beats the Twilio config, the incident lookup and any timeline row", async () => {
651
+ spies.findRule.mockResolvedValue(null as never);
652
+
653
+ await expect(
654
+ UserNotificationRuleService.executeNotificationRuleItem(
655
+ RULE_ID,
656
+ executeOptions(),
657
+ ),
658
+ ).rejects.toThrow(BadDataException);
659
+
660
+ expect(spies.twilio).not.toHaveBeenCalled();
661
+ expect(spies.incidentFind).not.toHaveBeenCalled();
662
+ expect(spies.timelineCreate).not.toHaveBeenCalled();
663
+ for (const sender of everySender()) {
664
+ expect(sender).not.toHaveBeenCalled();
665
+ }
666
+ });
667
+
668
+ test("the claim has ALREADY been consumed when the rule turns out to be missing", async () => {
669
+ spies.findRule.mockResolvedValue(null as never);
670
+
671
+ await expect(
672
+ UserNotificationRuleService.executeNotificationRuleItem(
673
+ RULE_ID,
674
+ executeOptions(),
675
+ ),
676
+ ).rejects.toThrow(BadDataException);
677
+
678
+ /*
679
+ * Pinned as current behaviour, unchanged by the split: the claim is
680
+ * written before the rule is read, so a rule deleted between scheduling
681
+ * and execution burns its claim and no later tick retries it. Deliberate
682
+ * (a missing rule is permanent), but it means the claim is not released.
683
+ */
684
+ expect(spies.claim).toHaveBeenCalledTimes(1);
685
+ });
686
+ });
687
+
688
+ /*
689
+ * ----------------------------------------------------------------------- *
690
+ * (C) The select the public half still passes.
691
+ * -----------------------------------------------------------------------
692
+ */
693
+
694
+ describe("the select handed to findOneById", () => {
695
+ async function captureFindArg(): Promise<FindOneByIdArg> {
696
+ stubDeliveryHalf();
697
+
698
+ await UserNotificationRuleService.executeNotificationRuleItem(
699
+ RULE_ID,
700
+ executeOptions(),
701
+ );
702
+
703
+ return spies.findRule.mock.calls[0]![0] as FindOneByIdArg;
704
+ }
705
+
706
+ test("targets the requested rule id, as root", async () => {
707
+ const arg: FindOneByIdArg = await captureFindArg();
708
+
709
+ expect(arg.id.toString()).toBe(RULE_ID.toString());
710
+ expect(arg.props.isRoot).toBe(true);
711
+ });
712
+
713
+ test("is EXACTLY this shape - a field lost in the split changes who gets paged", async () => {
714
+ const arg: FindOneByIdArg = await captureFindArg();
715
+
716
+ /*
717
+ * WHY EACH RELATION ALSO ASKS FOR ITS OWN userId, WHICH NO SENDER READS.
718
+ *
719
+ * A rule is a pair of columns that nothing in the ORM ever compares: its
720
+ * `userId` decides WHOSE page this is, and the method relation decides
721
+ * WHERE that page is delivered. A row where those two name different
722
+ * people routes one person's pages to another person's address, and it is
723
+ * invisible from both ends - the rules page still lists a rule and the
724
+ * on-call log still records a delivered notification.
725
+ *
726
+ * The write-side guards refuse to SAVE such a row. This select is what
727
+ * lets executeNotificationRuleItem refuse to ACT ON one that exists
728
+ * anyway: written before those guards landed, written by internal code
729
+ * running as root, or written down a path a future change forgets to
730
+ * route through them. getNotificationMethodsNotOwnedByRuleOwner compares
731
+ * the loaded relation's userId against the rule's, and it can only report
732
+ * a mismatch it can SEE - an unselected column arrives as `undefined` and
733
+ * is deliberately read as "no evidence", so dropping any one of these
734
+ * seven silently disables the backstop for that channel.
735
+ *
736
+ * Kept as an exact-shape assertion on purpose. This test caught the
737
+ * column being added, which is the whole argument for not relaxing it
738
+ * into a partial match: the select is a contract about who gets paged,
739
+ * and every future edit to it should have to come through here.
740
+ */
741
+ expect(arg.select).toEqual({
742
+ _id: true,
743
+ userId: true,
744
+ userCall: {
745
+ phone: true,
746
+ isVerified: true,
747
+ userId: true,
748
+ },
749
+ userSms: {
750
+ phone: true,
751
+ isVerified: true,
752
+ userId: true,
753
+ },
754
+ userWhatsApp: {
755
+ phone: true,
756
+ isVerified: true,
757
+ userId: true,
758
+ },
759
+ userTelegram: {
760
+ telegramChatId: true,
761
+ telegramUserHandle: true,
762
+ isVerified: true,
763
+ userId: true,
764
+ },
765
+ userWebhook: {
766
+ webhookUrl: true,
767
+ name: true,
768
+ secret: true,
769
+ userId: true,
770
+ },
771
+ userEmail: {
772
+ email: true,
773
+ isVerified: true,
774
+ userId: true,
775
+ },
776
+ userPush: {
777
+ deviceToken: true,
778
+ deviceType: true,
779
+ isVerified: true,
780
+ userId: true,
781
+ },
782
+ });
783
+ });
784
+
785
+ test.each<[string]>([
786
+ ["userCall"],
787
+ ["userSms"],
788
+ ["userWhatsApp"],
789
+ ["userTelegram"],
790
+ ["userEmail"],
791
+ ["userPush"],
792
+ ])(
793
+ "%s requests isVerified - every user-contactable channel is verification-gated",
794
+ async (channel: string) => {
795
+ const arg: FindOneByIdArg = await captureFindArg();
796
+ const selected: JSONObject = arg.select[channel] as JSONObject;
797
+
798
+ expect(selected).toBeDefined();
799
+ expect(selected["isVerified"]).toBe(true);
800
+ },
801
+ );
802
+
803
+ test.each<[string, string]>([
804
+ ["userCall", "phone"],
805
+ ["userSms", "phone"],
806
+ ["userWhatsApp", "phone"],
807
+ ["userTelegram", "telegramChatId"],
808
+ ["userEmail", "email"],
809
+ ["userPush", "deviceToken"],
810
+ ])(
811
+ "%s also requests its address column (%s), which the send gate reads alongside isVerified",
812
+ async (channel: string, addressColumn: string) => {
813
+ const arg: FindOneByIdArg = await captureFindArg();
814
+ const selected: JSONObject = arg.select[channel] as JSONObject;
815
+
816
+ expect(selected[addressColumn]).toBe(true);
817
+ },
818
+ );
819
+
820
+ test("userWebhook requests webhookUrl, name and secret - and no isVerified", async () => {
821
+ const arg: FindOneByIdArg = await captureFindArg();
822
+ const webhookSelect: JSONObject = arg.select["userWebhook"] as JSONObject;
823
+
824
+ /*
825
+ * Webhooks are the one user-contactable channel with no verification
826
+ * concept at all (UserWebhook has no isVerified column), so the delivery
827
+ * gate is `webhookUrl` alone. `secret` is not cosmetic: it signs the
828
+ * outgoing request, so an unselected secret ships UNSIGNED webhooks.
829
+ *
830
+ * `userId` is not read by the webhook sender either. It is the
831
+ * defence-in-depth column described on the exact-shape assertion above -
832
+ * the one the pre-delivery ownership check compares against the rule's
833
+ * own userId - and webhooks are the channel where a hijacked method
834
+ * matters most, because the attacker chooses the endpoint outright.
835
+ */
836
+ expect(webhookSelect).toEqual({
837
+ webhookUrl: true,
838
+ name: true,
839
+ secret: true,
840
+ userId: true,
841
+ });
842
+ expect(webhookSelect["isVerified"]).toBeUndefined();
843
+ });
844
+
845
+ test("userId is selected - the timeline row and every sender stamp it", async () => {
846
+ const arg: FindOneByIdArg = await captureFindArg();
847
+
848
+ expect(arg.select["userId"]).toBe(true);
849
+ expect(arg.select["_id"]).toBe(true);
850
+ });
851
+ });
852
+
853
+ /*
854
+ * ----------------------------------------------------------------------- *
855
+ * (D) The seam itself: what crosses from one half to the other.
856
+ * -----------------------------------------------------------------------
857
+ */
858
+
859
+ describe("the seam between the two halves", () => {
860
+ test("the delivery half is entered exactly once per execution", async () => {
861
+ const deliver: jest.SpyInstance = stubDeliveryHalf();
862
+
863
+ await UserNotificationRuleService.executeNotificationRuleItem(
864
+ RULE_ID,
865
+ executeOptions(),
866
+ );
867
+
868
+ expect(deliver).toHaveBeenCalledTimes(1);
869
+ });
870
+
871
+ test("the rule object findOneById returned is handed over BY REFERENCE, unchanged", async () => {
872
+ const rule: UserNotificationRule = loadedRule({
873
+ userEmail: verifiedUserEmail(),
874
+ } as unknown as JSONObject);
875
+ spies.findRule.mockResolvedValue(rule as never);
876
+ const deliver: jest.SpyInstance = stubDeliveryHalf();
877
+
878
+ await UserNotificationRuleService.executeNotificationRuleItem(
879
+ RULE_ID,
880
+ executeOptions(),
881
+ );
882
+
883
+ /*
884
+ * Identity, not shape. A copy would be a real regression: the channel
885
+ * blocks read hydrated RELATIONS (userEmail.email, userEmail.isVerified),
886
+ * and any reshaping on the way across is exactly how a relation turns
887
+ * into a bare FK and a verified responder stops being contactable.
888
+ */
889
+ expect(deliver.mock.calls[0]![0]).toBe(rule);
890
+ });
891
+
892
+ test("the caller's options bag is handed over BY REFERENCE, unchanged", async () => {
893
+ const options: ExecuteOptions = executeOptions();
894
+ const deliver: jest.SpyInstance = stubDeliveryHalf();
895
+
896
+ await UserNotificationRuleService.executeNotificationRuleItem(
897
+ RULE_ID,
898
+ options,
899
+ );
900
+
901
+ expect(deliver.mock.calls[0]![1]).toBe(options);
902
+ });
903
+
904
+ test("the public half itself does no delivery work - it is all beyond the seam", async () => {
905
+ stubDeliveryHalf();
906
+
907
+ await UserNotificationRuleService.executeNotificationRuleItem(
908
+ RULE_ID,
909
+ executeOptions(),
910
+ );
911
+
912
+ /*
913
+ * With the delivery half stubbed out, NOTHING should be left running in
914
+ * the public method: no Twilio config, no trigger-entity lookup, no
915
+ * timeline row, no send. If any of these fire, part of the body was left
916
+ * behind on the claim-and-load side, where the fallback cannot reuse it.
917
+ */
918
+ expect(spies.twilio).not.toHaveBeenCalled();
919
+ expect(spies.incidentFind).not.toHaveBeenCalled();
920
+ expect(spies.alertFind).not.toHaveBeenCalled();
921
+ expect(spies.alertEpisodeFind).not.toHaveBeenCalled();
922
+ expect(spies.incidentEpisodeFind).not.toHaveBeenCalled();
923
+ expect(spies.timelineCreate).not.toHaveBeenCalled();
924
+ for (const sender of everySender()) {
925
+ expect(sender).not.toHaveBeenCalled();
926
+ }
927
+ });
928
+
929
+ test("the public method still resolves to undefined - the delivery boolean is swallowed", async () => {
930
+ const deliver: jest.SpyInstance = stubDeliveryHalf();
931
+ deliver.mockResolvedValue(false as never);
932
+
933
+ /*
934
+ * The delivery half reports whether anything was dispatched, and the
935
+ * fallback branches on that. The rule-driven path deliberately does not:
936
+ * its signature is Promise<void> and callers await it for sequencing
937
+ * only. Returning the boolean here would be a public-API change.
938
+ */
939
+ await expect(
940
+ UserNotificationRuleService.executeNotificationRuleItem(
941
+ RULE_ID,
942
+ executeOptions(),
943
+ ),
944
+ ).resolves.toBeUndefined();
945
+ });
946
+
947
+ test("a throwing delivery half propagates out of the public method", async () => {
948
+ const deliver: jest.SpyInstance = stubDeliveryHalf();
949
+ deliver.mockRejectedValue(
950
+ new BadDataException(
951
+ "Incident, Alert, Alert Episode, or Incident Episode not found.",
952
+ ) as never,
953
+ );
954
+
955
+ /*
956
+ * The delivery half is AWAITED, not fired and forgotten. That is what
957
+ * lets ExecutePendingExecutions turn a missing trigger entity into an
958
+ * Error on the log instead of an unhandled rejection.
959
+ */
960
+ await expect(
961
+ UserNotificationRuleService.executeNotificationRuleItem(
962
+ RULE_ID,
963
+ executeOptions(),
964
+ ),
965
+ ).rejects.toThrow(
966
+ "Incident, Alert, Alert Episode, or Incident Episode not found.",
967
+ );
968
+ });
969
+
970
+ test("end to end, unstubbed, the rule loaded by id still reaches a sender", async () => {
971
+ spies.findRule.mockResolvedValue(
972
+ loadedRule({
973
+ userEmail: verifiedUserEmail(),
974
+ } as unknown as JSONObject) as never,
975
+ );
976
+
977
+ await UserNotificationRuleService.executeNotificationRuleItem(
978
+ RULE_ID,
979
+ executeOptions(),
980
+ );
981
+
982
+ expect(spies.mail).toHaveBeenCalledTimes(1);
983
+ expect(timelineRows).toHaveLength(1);
984
+ expect(timelineRows[0]?.status).toBe(UserNotificationStatus.Sending);
985
+ expect(timelineRows[0]?.statusMessage).toContain(RESPONDER_EMAIL);
986
+ // A rule that DOES have an id still stamps it on the timeline row.
987
+ expect(timelineRows[0]?.userNotificationRuleId?.toString()).toBe(
988
+ RULE_ID.toString(),
989
+ );
990
+ expect(timelineRows[0]?.userEmailId?.toString()).toBe(
991
+ EMAIL_METHOD_ID.toString(),
992
+ );
993
+ });
994
+ });
995
+
996
+ /*
997
+ * ----------------------------------------------------------------------- *
998
+ * (E) The delivery half driven directly with an UNSAVED rule.
999
+ *
1000
+ * This is what the fallback does, and it is the regression guard for
1001
+ * blocker B1.
1002
+ * -----------------------------------------------------------------------
1003
+ */
1004
+
1005
+ describe("the delivery half accepts an unsaved, id-less rule", () => {
1006
+ test("the rule the fallback builds really has no id", () => {
1007
+ const rule: UserNotificationRule = unsavedFallbackRule();
1008
+
1009
+ /*
1010
+ * Guarding the guard. `id` is a getter over `_id`, so a rule that was
1011
+ * never saved reports null - and every assertion below about the
1012
+ * timeline row depends on that actually being the case.
1013
+ */
1014
+ expect(rule.id).toBeNull();
1015
+ expect(rule._id).toBeUndefined();
1016
+ });
1017
+
1018
+ test("an id-less email rule still writes a timeline row and dispatches", async () => {
1019
+ const rule: UserNotificationRule = unsavedFallbackRule();
1020
+ rule.userEmail = verifiedUserEmail();
1021
+ rule.userEmailId = EMAIL_METHOD_ID;
1022
+
1023
+ const dispatched: boolean =
1024
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
1025
+
1026
+ /*
1027
+ * BLOCKER B1. UserOnCallLogTimeline.userNotificationRuleId used to be
1028
+ * NOT NULL, so this create() threw for every fallback delivery - before
1029
+ * a single page left the process. The column is nullable now and
1030
+ * buildLogTimelineItem only sets the id when the rule has one.
1031
+ */
1032
+ expect(dispatched).toBe(true);
1033
+ expect(timelineRows).toHaveLength(1);
1034
+ expect(timelineRows[0]?.userNotificationRuleId).toBeUndefined();
1035
+ expect(timelineRows[0]?.status).toBe(UserNotificationStatus.Sending);
1036
+ expect(timelineRows[0]?.statusMessage).toContain(RESPONDER_EMAIL);
1037
+ expect(spies.mail).toHaveBeenCalledTimes(1);
1038
+ });
1039
+
1040
+ test("the id-less row still carries everything a reader needs", async () => {
1041
+ const rule: UserNotificationRule = unsavedFallbackRule();
1042
+ rule.userEmail = verifiedUserEmail();
1043
+ rule.userEmailId = EMAIL_METHOD_ID;
1044
+
1045
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
1046
+
1047
+ /*
1048
+ * Losing the rule id must not quietly cost the row its other anchors -
1049
+ * an operator opening the on-call timeline has to see which log, which
1050
+ * user, which escalation and which incident this page belonged to.
1051
+ */
1052
+ expect(timelineRows[0]?.userId?.toString()).toBe(USER_ID.toString());
1053
+ expect(timelineRows[0]?.projectId?.toString()).toBe(
1054
+ PROJECT_ID.toString(),
1055
+ );
1056
+ expect(timelineRows[0]?.userNotificationLogId?.toString()).toBe(
1057
+ LOG_ID.toString(),
1058
+ );
1059
+ expect(timelineRows[0]?.userNotificationEventType).toBe(
1060
+ UserNotificationEventType.IncidentCreated,
1061
+ );
1062
+ expect(timelineRows[0]?.triggeredByIncidentId?.toString()).toBe(
1063
+ INCIDENT_ID.toString(),
1064
+ );
1065
+ expect(timelineRows[0]?.onCallDutyPolicyId?.toString()).toBe(
1066
+ POLICY_ID.toString(),
1067
+ );
1068
+ expect(
1069
+ timelineRows[0]?.onCallDutyPolicyEscalationRuleId?.toString(),
1070
+ ).toBe(ESCALATION_RULE_ID.toString());
1071
+ expect(timelineRows[0]?.userBelongsToTeamId?.toString()).toBe(
1072
+ TEAM_ID.toString(),
1073
+ );
1074
+ // The method FK is read off the RELATION, which is all the fallback sets.
1075
+ expect(timelineRows[0]?.userEmailId?.toString()).toBe(
1076
+ EMAIL_METHOD_ID.toString(),
1077
+ );
1078
+ });
1079
+
1080
+ test("an id-less push rule dispatches too - push is the fallback's first choice", async () => {
1081
+ const rule: UserNotificationRule = unsavedFallbackRule();
1082
+ rule.userPush = verifiedUserPush();
1083
+ rule.userPushId = PUSH_METHOD_ID;
1084
+
1085
+ const dispatched: boolean =
1086
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
1087
+
1088
+ expect(dispatched).toBe(true);
1089
+ expect(spies.push).toHaveBeenCalledTimes(1);
1090
+ expect(timelineRows).toHaveLength(1);
1091
+ expect(timelineRows[0]?.userNotificationRuleId).toBeUndefined();
1092
+ expect(timelineRows[0]?.userPushId?.toString()).toBe(
1093
+ PUSH_METHOD_ID.toString(),
1094
+ );
1095
+ });
1096
+
1097
+ test("driving the delivery half directly claims nothing and loads no rule", async () => {
1098
+ const rule: UserNotificationRule = unsavedFallbackRule();
1099
+ rule.userEmail = verifiedUserEmail();
1100
+ rule.userEmailId = EMAIL_METHOD_ID;
1101
+
1102
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
1103
+
1104
+ /*
1105
+ * The two things the public half does are exactly the two things a
1106
+ * rule with no database row cannot do. If either had been left inside
1107
+ * the delivery half, the fallback would try to claim a rule id it does
1108
+ * not have and read a row that does not exist.
1109
+ */
1110
+ expect(spies.claim).not.toHaveBeenCalled();
1111
+ expect(spies.findRule).not.toHaveBeenCalled();
1112
+ });
1113
+
1114
+ test("the unsaved rule is never persisted on the way through", async () => {
1115
+ const rule: UserNotificationRule = unsavedFallbackRule();
1116
+ rule.userEmail = verifiedUserEmail();
1117
+ rule.userEmailId = EMAIL_METHOD_ID;
1118
+
1119
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
1120
+
1121
+ /*
1122
+ * The user never asked for this rule. Saving it would silently rewrite
1123
+ * their notification configuration behind their back, and the next real
1124
+ * page would match a rule they did not create.
1125
+ */
1126
+ expect(spies.createRule).not.toHaveBeenCalled();
1127
+ expect(rule.id).toBeNull();
1128
+ });
1129
+
1130
+ test("two delivery calls build two DISTINCT timeline instances", async () => {
1131
+ const pushRule: UserNotificationRule = unsavedFallbackRule();
1132
+ pushRule.userPush = verifiedUserPush();
1133
+ pushRule.userPushId = PUSH_METHOD_ID;
1134
+
1135
+ const emailRule: UserNotificationRule = unsavedFallbackRule();
1136
+ emailRule.userEmail = verifiedUserEmail();
1137
+ emailRule.userEmailId = EMAIL_METHOD_ID;
1138
+
1139
+ await deliveryHalf().deliverNotificationForRule(
1140
+ pushRule,
1141
+ executeOptions(),
1142
+ );
1143
+ await deliveryHalf().deliverNotificationForRule(
1144
+ emailRule,
1145
+ executeOptions(),
1146
+ );
1147
+
1148
+ /*
1149
+ * Why the fallback calls this once PER CHANNEL with a freshly built
1150
+ * rule instead of looping channels inside one call: the timeline item is
1151
+ * a single mutable instance per call, and after the first create() it
1152
+ * carries an _id - so a second create() with the SAME instance UPDATEs
1153
+ * the row the first channel wrote instead of inserting a second one. Two
1154
+ * calls means two instances, which is what keeps the second page
1155
+ * visible.
1156
+ */
1157
+ expect(timelineInstances).toHaveLength(2);
1158
+ expect(timelineInstances[0]).not.toBe(timelineInstances[1]);
1159
+ expect(spies.push).toHaveBeenCalledTimes(1);
1160
+ expect(spies.mail).toHaveBeenCalledTimes(1);
1161
+ });
1162
+
1163
+ test("an id-less rule with no contactable method dispatches nothing and returns false", async () => {
1164
+ const rule: UserNotificationRule = unsavedFallbackRule();
1165
+
1166
+ const dispatched: boolean =
1167
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
1168
+
1169
+ /*
1170
+ * The return value is the fallback's only evidence. "Resolved without
1171
+ * throwing" is NOT "paged": a false here is what stops the operator
1172
+ * being told the responder was reached on a channel that sent nothing.
1173
+ */
1174
+ expect(dispatched).toBe(false);
1175
+ for (const sender of everySender()) {
1176
+ expect(sender).not.toHaveBeenCalled();
1177
+ }
1178
+ expect(timelineRows).toHaveLength(0);
1179
+ });
1180
+
1181
+ test("an id-less rule whose method is UNVERIFIED is not contacted", async () => {
1182
+ const rule: UserNotificationRule = unsavedFallbackRule();
1183
+ const userEmail: UserEmail = verifiedUserEmail();
1184
+ userEmail.isVerified = false;
1185
+ rule.userEmail = userEmail;
1186
+ rule.userEmailId = EMAIL_METHOD_ID;
1187
+
1188
+ const dispatched: boolean =
1189
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
1190
+
1191
+ /*
1192
+ * The verification gates are inside the delivery half, so they apply to
1193
+ * the fallback exactly as they apply to a configured rule. A fallback
1194
+ * that could page unverified addresses would be a way to send mail to an
1195
+ * address nobody proved they own.
1196
+ */
1197
+ expect(dispatched).toBe(false);
1198
+ expect(spies.mail).not.toHaveBeenCalled();
1199
+ expect(timelineRows).toHaveLength(1);
1200
+ expect(timelineRows[0]?.status).toBe(UserNotificationStatus.Error);
1201
+ expect(timelineRows[0]?.statusMessage).toContain("not verified");
1202
+ });
1203
+
1204
+ test("a missing trigger entity still throws, even for an id-less rule", async () => {
1205
+ spies.incidentFind.mockResolvedValue(null as never);
1206
+
1207
+ const rule: UserNotificationRule = unsavedFallbackRule();
1208
+ rule.userEmail = verifiedUserEmail();
1209
+ rule.userEmailId = EMAIL_METHOD_ID;
1210
+
1211
+ await expect(
1212
+ deliveryHalf().deliverNotificationForRule(rule, executeOptions()),
1213
+ ).rejects.toThrow(
1214
+ "Incident, Alert, Alert Episode, or Incident Episode not found.",
1215
+ );
1216
+
1217
+ expect(spies.mail).not.toHaveBeenCalled();
1218
+ });
1219
+ });
1220
+
1221
+ /*
1222
+ * ----------------------------------------------------------------------- *
1223
+ * (F) projectTwilioConfig: resolved once, in the delivery half.
1224
+ * -----------------------------------------------------------------------
1225
+ */
1226
+
1227
+ describe("the project Twilio config", () => {
1228
+ test("is resolved exactly once per delivery, from options.projectId", async () => {
1229
+ const options: ExecuteOptions = executeOptions();
1230
+ spies.findRule.mockResolvedValue(
1231
+ loadedRule({
1232
+ userSms: verifiedUserSms(),
1233
+ } as unknown as JSONObject) as never,
1234
+ );
1235
+
1236
+ await UserNotificationRuleService.executeNotificationRuleItem(
1237
+ RULE_ID,
1238
+ options,
1239
+ );
1240
+
1241
+ expect(spies.twilio).toHaveBeenCalledTimes(1);
1242
+ /*
1243
+ * Identity against the caller's own projectId. The channel blocks below
1244
+ * pass the TRIGGER entity's projectId to the senders, so reading the
1245
+ * config off the incident instead of the options would look identical in
1246
+ * every normal case and diverge only in the odd one.
1247
+ */
1248
+ expect(spies.twilio.mock.calls[0]![0]).toBe(options.projectId);
1249
+ });
1250
+
1251
+ test("is resolved AFTER the rule is loaded and BEFORE any timeline row or send", async () => {
1252
+ spies.findRule.mockResolvedValue(
1253
+ loadedRule({
1254
+ userSms: verifiedUserSms(),
1255
+ } as unknown as JSONObject) as never,
1256
+ );
1257
+
1258
+ await UserNotificationRuleService.executeNotificationRuleItem(
1259
+ RULE_ID,
1260
+ executeOptions(),
1261
+ );
1262
+
1263
+ /*
1264
+ * The ordering IS the extraction boundary: the config lookup was the
1265
+ * first statement of the old body's second half, and it has to stay on
1266
+ * the delivery side or the fallback never sees it.
1267
+ */
1268
+ expect(spies.findRule.mock.invocationCallOrder[0]).toBeLessThan(
1269
+ spies.twilio.mock.invocationCallOrder[0] as number,
1270
+ );
1271
+ expect(spies.twilio.mock.invocationCallOrder[0]).toBeLessThan(
1272
+ spies.timelineCreate.mock.invocationCallOrder[0] as number,
1273
+ );
1274
+ expect(spies.twilio.mock.invocationCallOrder[0]).toBeLessThan(
1275
+ spies.sms.mock.invocationCallOrder[0] as number,
1276
+ );
1277
+ });
1278
+
1279
+ test("the resolved config object reaches SmsService.sendSms by reference", async () => {
1280
+ const twilioConfig: TwilioConfig = fakeTwilioConfig();
1281
+ spies.twilio.mockResolvedValue(twilioConfig as never);
1282
+ spies.findRule.mockResolvedValue(
1283
+ loadedRule({
1284
+ userSms: verifiedUserSms(),
1285
+ } as unknown as JSONObject) as never,
1286
+ );
1287
+
1288
+ await UserNotificationRuleService.executeNotificationRuleItem(
1289
+ RULE_ID,
1290
+ executeOptions(),
1291
+ );
1292
+
1293
+ expect(spies.sms).toHaveBeenCalledTimes(1);
1294
+ /*
1295
+ * A project with its own Twilio account must be billed on that account.
1296
+ * Dropping this key does not fail - it quietly sends every on-call SMS
1297
+ * from the global OneUptime number.
1298
+ */
1299
+ expect(sentSmsOptions().customTwilioConfig).toBe(twilioConfig);
1300
+ });
1301
+
1302
+ test("no project config resolves to undefined and is still passed through", async () => {
1303
+ spies.twilio.mockResolvedValue(undefined as never);
1304
+ spies.findRule.mockResolvedValue(
1305
+ loadedRule({
1306
+ userSms: verifiedUserSms(),
1307
+ } as unknown as JSONObject) as never,
1308
+ );
1309
+
1310
+ await UserNotificationRuleService.executeNotificationRuleItem(
1311
+ RULE_ID,
1312
+ executeOptions(),
1313
+ );
1314
+
1315
+ // undefined is the signal for "use the global config", not a bug.
1316
+ expect(sentSmsOptions().customTwilioConfig).toBeUndefined();
1317
+ });
1318
+
1319
+ test("a fallback-style delivery resolves the PROJECT's config too", async () => {
1320
+ const twilioConfig: TwilioConfig = fakeTwilioConfig();
1321
+ spies.twilio.mockResolvedValue(twilioConfig as never);
1322
+
1323
+ const rule: UserNotificationRule = unsavedFallbackRule();
1324
+ rule.userSms = verifiedUserSms();
1325
+ rule.userSmsId = SMS_METHOD_ID;
1326
+
1327
+ const options: ExecuteOptions = executeOptions();
1328
+ await deliveryHalf().deliverNotificationForRule(rule, options);
1329
+
1330
+ /*
1331
+ * The fallback picks a paid channel only when the responder has no
1332
+ * zero-cost method, so when it does reach SMS the project's own Twilio
1333
+ * account is the one that must be charged.
1334
+ */
1335
+ expect(spies.twilio).toHaveBeenCalledTimes(1);
1336
+ expect(spies.twilio.mock.calls[0]![0]).toBe(options.projectId);
1337
+ expect(sentSmsOptions().customTwilioConfig).toBe(twilioConfig);
1338
+ });
1339
+
1340
+ test("it is hoisted above the channel blocks - two channels, still one lookup", async () => {
1341
+ /*
1342
+ * A rule with two methods is not something the product creates (a rule
1343
+ * carries exactly one), and the fallback deliberately never builds one -
1344
+ * see the distinct-instances test above for why. It is used HERE only to
1345
+ * prove the config read sits above the channel blocks rather than inside
1346
+ * them: were it per-block, this would be two reads.
1347
+ */
1348
+ spies.findRule.mockResolvedValue(
1349
+ loadedRule({
1350
+ userEmail: verifiedUserEmail(),
1351
+ userSms: verifiedUserSms(),
1352
+ } as unknown as JSONObject) as never,
1353
+ );
1354
+
1355
+ await UserNotificationRuleService.executeNotificationRuleItem(
1356
+ RULE_ID,
1357
+ executeOptions(),
1358
+ );
1359
+
1360
+ expect(spies.mail).toHaveBeenCalledTimes(1);
1361
+ expect(spies.sms).toHaveBeenCalledTimes(1);
1362
+ expect(spies.twilio).toHaveBeenCalledTimes(1);
1363
+ });
1364
+
1365
+ test("a Twilio config read that rejects takes the whole delivery down", async () => {
1366
+ spies.twilio.mockRejectedValue(
1367
+ new Error("project config read failed") as never,
1368
+ );
1369
+ spies.findRule.mockResolvedValue(
1370
+ loadedRule({
1371
+ userSms: verifiedUserSms(),
1372
+ } as unknown as JSONObject) as never,
1373
+ );
1374
+
1375
+ /*
1376
+ * Pinned as current behaviour: the lookup is the first awaited statement
1377
+ * of the delivery half and is not guarded, so a failing project-config
1378
+ * read stops the page rather than falling back to the global config.
1379
+ * Loud, and the log ends up Error - but it is a real single point of
1380
+ * failure for channels that do not need Twilio at all.
1381
+ */
1382
+ await expect(
1383
+ UserNotificationRuleService.executeNotificationRuleItem(
1384
+ RULE_ID,
1385
+ executeOptions(),
1386
+ ),
1387
+ ).rejects.toThrow("project config read failed");
1388
+
1389
+ expect(spies.sms).not.toHaveBeenCalled();
1390
+ expect(spies.timelineCreate).not.toHaveBeenCalled();
1391
+ });
1392
+ });
1393
+ });