@oneuptime/common 12.0.13 → 12.0.14

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 (376) hide show
  1. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +14 -0
  2. package/Models/DatabaseModels/UserCall.ts +94 -3
  3. package/Models/DatabaseModels/UserEmail.ts +94 -3
  4. package/Models/DatabaseModels/UserIncomingCallNumber.ts +94 -3
  5. package/Models/DatabaseModels/UserPush.ts +37 -0
  6. package/Models/DatabaseModels/UserSMS.ts +94 -3
  7. package/Models/DatabaseModels/UserWhatsApp.ts +93 -2
  8. package/Server/API/BaseAPI.ts +79 -14
  9. package/Server/API/UserCallAPI.ts +53 -45
  10. package/Server/API/UserEmailAPI.ts +53 -44
  11. package/Server/API/UserIncomingCallNumberAPI.ts +48 -38
  12. package/Server/API/UserNotificationMethodAdminAPI.ts +481 -0
  13. package/Server/API/UserPushAPI.ts +126 -2
  14. package/Server/API/UserSmsAPI.ts +53 -44
  15. package/Server/API/UserWhatsAppAPI.ts +53 -50
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.ts +154 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.ts +17 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.ts +45 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  20. package/Server/Middleware/VerificationCodeRateLimit.ts +586 -0
  21. package/Server/Services/AnalyticsDatabaseService.ts +169 -0
  22. package/Server/Services/DatabaseService.ts +101 -0
  23. package/Server/Services/LogAggregationService.ts +5 -0
  24. package/Server/Services/PushNotificationService.ts +127 -12
  25. package/Server/Services/TeamMemberService.ts +53 -13
  26. package/Server/Services/UserCallService.ts +55 -24
  27. package/Server/Services/UserEmailService.ts +83 -17
  28. package/Server/Services/UserIncomingCallNumberService.ts +49 -85
  29. package/Server/Services/UserNotificationMethodAdminService.ts +1527 -0
  30. package/Server/Services/UserNotificationRuleService.ts +26 -0
  31. package/Server/Services/UserPushService.ts +89 -0
  32. package/Server/Services/UserSmsService.ts +50 -17
  33. package/Server/Services/UserWhatsAppService.ts +48 -15
  34. package/Server/Types/Database/QueryHelper.ts +30 -0
  35. package/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.ts +59 -0
  36. package/Server/Utils/ChannelVerification.ts +510 -0
  37. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +13 -16
  38. package/Server/Utils/Monitor/MonitorAlert.ts +24 -21
  39. package/Server/Utils/Monitor/MonitorIncident.ts +21 -18
  40. package/Server/Utils/Monitor/MonitorResourceContext.ts +107 -0
  41. package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +442 -0
  42. package/Server/Utils/Monitor/SeriesResourceLabels.ts +3 -3
  43. package/Server/Utils/Monitor/SeriesResourceLinker.ts +96 -28
  44. package/Server/Utils/TotpAuth.ts +137 -9
  45. package/Server/Utils/UserRegistrationToken.ts +182 -0
  46. package/Server/Utils/VerificationCode.ts +134 -0
  47. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +173 -94
  48. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +1151 -0
  49. package/Tests/App/Dashboard/AdminUserOnCallPages.test.tsx +905 -0
  50. package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +338 -0
  51. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1 -1
  52. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +28 -0
  53. package/Tests/Models/UserPushCriticalAlertColumn.test.ts +172 -0
  54. package/Tests/Server/API/BaseAPIGetListParallel.test.ts +519 -0
  55. package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +543 -0
  56. package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +108 -18
  57. package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +963 -0
  58. package/Tests/Server/API/UserPushCriticalAlertsApi.test.ts +114 -0
  59. package/Tests/Server/API/UserSmsApi.test.ts +107 -14
  60. package/Tests/Server/API/UserTotpAuthAPI.test.ts +427 -0
  61. package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +315 -0
  62. package/Tests/Server/Middleware/VerificationCodeRateLimit.test.ts +775 -0
  63. package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +10 -62
  64. package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +33 -13
  65. package/Tests/Server/Services/AnalyticsDatabaseSortKeyBoundary.test.ts +658 -0
  66. package/Tests/Server/Services/CriticalOnCallAlertDelivery.test.ts +458 -0
  67. package/Tests/Server/Services/CriticalPushAlertPayload.test.ts +301 -0
  68. package/Tests/Server/Services/DatabaseServiceAtomicIncrement.test.ts +143 -0
  69. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1 -0
  70. package/Tests/Server/Services/LogAggregationScanMemory.test.ts +421 -0
  71. package/Tests/Server/Services/LogAggregationService.test.ts +2 -2
  72. package/Tests/Server/Services/NotificationChannelCodeIssuance.test.ts +401 -0
  73. package/Tests/Server/Services/PushNotificationDeliveryOptions.test.ts +204 -0
  74. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +21 -1
  75. package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +290 -0
  76. package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +948 -0
  77. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1 -0
  78. package/Tests/Server/Services/UserPushCriticalAlertToggle.test.ts +255 -0
  79. package/Tests/Server/Services/UserTotpAuthEnrolment.test.ts +218 -0
  80. package/Tests/Server/TestingUtils/AuthenticatorApp.ts +248 -0
  81. package/Tests/Server/Types/Database/Permissions/NotificationChannelVerificationColumns.test.ts +135 -0
  82. package/Tests/Server/Types/Database/Permissions/OnCallScheduleRelationSelect.test.ts +504 -0
  83. package/Tests/Server/Types/Database/QueryHelperFindWithSameTextAnyOf.test.ts +91 -0
  84. package/Tests/Server/Types/Workflow/Components/JsonToText.test.ts +384 -0
  85. package/Tests/Server/Types/Workflow/Components/MergeJson.test.ts +403 -0
  86. package/Tests/Server/Utils/Browser.test.ts +162 -0
  87. package/Tests/Server/Utils/ChannelVerification.test.ts +689 -0
  88. package/Tests/Server/Utils/Express.test.ts +371 -0
  89. package/Tests/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.test.ts +707 -0
  90. package/Tests/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.test.ts +698 -0
  91. package/Tests/Server/Utils/Monitor/Criteria/IncomingEmailBodyCriteria.test.ts +243 -0
  92. package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestBodyCriteria.test.ts +278 -0
  93. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +160 -20
  94. package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +13 -8
  95. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +162 -18
  96. package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +349 -0
  97. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +690 -0
  98. package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +7 -2
  99. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +92 -18
  100. package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +267 -0
  101. package/Tests/Server/Utils/Telemetry/OneuptimeLabel.test.ts +439 -0
  102. package/Tests/Server/Utils/TotpAuth.test.ts +719 -0
  103. package/Tests/Server/Utils/UserRegistrationToken.test.ts +322 -0
  104. package/Tests/Server/Utils/VerificationCode.test.ts +296 -0
  105. package/Tests/Types/AutoRemediation/AutoRemediationSuggestionStatus.test.ts +192 -0
  106. package/Tests/Types/Call/CallRequest.test.ts +189 -0
  107. package/Tests/Types/Dashboard/DashboardSize.test.ts +226 -0
  108. package/Tests/Types/Incident/IncidentSlaStatus.test.ts +191 -0
  109. package/Tests/Types/Metrics/MetricDashboardMetricType.test.ts +278 -0
  110. package/Tests/Types/Metrics/MetricPipelineRuleType.test.ts +517 -0
  111. package/Tests/Types/Monitor/IncomingMonitorDefaultCriteria.test.ts +470 -0
  112. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +6 -4
  113. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +262 -5
  114. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
  115. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
  116. package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +905 -0
  117. package/Tests/Types/Service/ServiceLanguage.test.ts +255 -0
  118. package/Tests/Types/TextRandomGeneration.test.ts +211 -0
  119. package/Tests/UI/Components/Button.test.tsx +175 -1
  120. package/Tests/UI/Components/CodeBlockLanguages.test.tsx +236 -0
  121. package/Tests/UI/Components/CommandPalette/CommandPalette.test.tsx +568 -0
  122. package/Tests/UI/Components/CommandPalette/CommandPaletteKeyboard.test.tsx +239 -0
  123. package/Tests/UI/Components/CommandPalette/CommandPaletteProviders.test.tsx +400 -0
  124. package/Tests/UI/Components/CommandPalette/PaletteFilter.test.ts +234 -0
  125. package/Tests/UI/Components/CommandPalette/RecentCommands.test.ts +97 -0
  126. package/Tests/UI/Components/CountModelSideMenuItemGuard.test.tsx +198 -0
  127. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +1 -1
  128. package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +267 -0
  129. package/Tests/UI/Components/List.test.tsx +9 -2
  130. package/Tests/UI/Components/ListLoadingStates.test.tsx +173 -0
  131. package/Tests/UI/Components/MarkdownLazy.test.tsx +113 -0
  132. package/Tests/UI/Components/MarkdownMermaidRetry.test.tsx +110 -0
  133. package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +8 -0
  134. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +692 -0
  135. package/Tests/UI/Components/MoreMenuMotion.test.tsx +118 -0
  136. package/Tests/UI/Components/NavBarCommandKGating.test.tsx +178 -0
  137. package/Tests/UI/Components/OrderedStatesList.test.tsx +19 -2
  138. package/Tests/UI/Components/SideOverMotion.test.tsx +109 -0
  139. package/Tests/UI/Components/Skeleton.test.tsx +71 -0
  140. package/Tests/UI/Components/TableLoadingStates.test.tsx +279 -0
  141. package/Tests/UI/Components/Tabs.test.tsx +24 -0
  142. package/Tests/UI/Components/Toast.test.tsx +130 -7
  143. package/Tests/UI/Components/ToastStacking.test.tsx +198 -0
  144. package/Tests/UI/Utils/Dropdown.test.ts +423 -0
  145. package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +122 -0
  146. package/Tests/UI/Utils/ModelListCache.test.ts +338 -0
  147. package/Tests/UI/Utils/ProjectListCacheInvalidation.test.ts +225 -0
  148. package/Tests/Utils/API.test.ts +16 -2
  149. package/Tests/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.test.ts +347 -0
  150. package/Tests/Utils/Dashboard/Components/DashboardListSharedArgs.test.ts +259 -0
  151. package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +466 -0
  152. package/Tests/Utils/Rum/UrlScrubberSegments.test.ts +362 -0
  153. package/Types/Email/EmailTemplateType.ts +1 -0
  154. package/Types/Monitor/MonitorCriteriaInstance.ts +41 -20
  155. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +131 -8
  156. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +48 -8
  157. package/Types/Monitor/ServiceAlertTemplates.ts +1352 -0
  158. package/Types/Permission.ts +35 -0
  159. package/Types/PushNotification/AndroidNotificationChannel.ts +26 -0
  160. package/Types/PushNotification/PushNotificationMessage.ts +15 -0
  161. package/Types/PushNotification/PushNotificationRequest.ts +8 -16
  162. package/Types/Service/ServiceLanguage.ts +144 -0
  163. package/Types/Text.ts +111 -19
  164. package/UI/Components/Button/Button.tsx +27 -14
  165. package/UI/Components/CodeBlock/CodeBlock.tsx +54 -7
  166. package/UI/Components/CodeBlock/LanguageRegistry.ts +103 -0
  167. package/UI/Components/CommandPalette/CommandPalette.tsx +790 -0
  168. package/UI/Components/CommandPalette/PaletteFilter.ts +196 -0
  169. package/UI/Components/CommandPalette/PaletteRow.tsx +173 -0
  170. package/UI/Components/CommandPalette/RecentCommands.ts +57 -0
  171. package/UI/Components/CommandPalette/Types.ts +49 -0
  172. package/UI/Components/CommandPalette/UseProviderSearch.ts +129 -0
  173. package/UI/Components/Dropdown/Dropdown.tsx +6 -1
  174. package/UI/Components/Feed/FeedItem.tsx +1 -1
  175. package/UI/Components/List/List.tsx +37 -5
  176. package/UI/Components/List/ListSkeleton.tsx +54 -0
  177. package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +6 -1
  178. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +71 -26
  179. package/UI/Components/Modal/Modal.tsx +2 -2
  180. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  181. package/UI/Components/ModelTable/useCustomFieldColumns.ts +11 -5
  182. package/UI/Components/MoreMenu/MoreMenu.tsx +39 -1
  183. package/UI/Components/Navbar/NavBar.tsx +14 -1
  184. package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +50 -5
  185. package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +40 -1
  186. package/UI/Components/SideOver/SideOver.tsx +37 -2
  187. package/UI/Components/Skeleton/Skeleton.tsx +53 -0
  188. package/UI/Components/Table/Table.tsx +74 -44
  189. package/UI/Components/Table/TableSkeletonRows.tsx +141 -0
  190. package/UI/Components/Tabs/Tab.tsx +1 -1
  191. package/UI/Components/Toast/Toast.tsx +118 -53
  192. package/UI/Components/Toast/ToastInit.tsx +82 -32
  193. package/UI/Styles/Theme.css +40 -0
  194. package/UI/Utils/ModelAPI/ModelAPI.ts +20 -10
  195. package/UI/Utils/ModelListCache.ts +188 -0
  196. package/UI/Utils/Project.ts +29 -0
  197. package/Utils/API.ts +6 -1
  198. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +14 -0
  199. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/UserCall.js +101 -3
  201. package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/UserEmail.js +101 -3
  203. package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +101 -3
  205. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/UserPush.js +38 -0
  207. package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/UserSMS.js +101 -3
  209. package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/UserWhatsApp.js +100 -2
  211. package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
  212. package/build/dist/Server/API/BaseAPI.js +69 -13
  213. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  214. package/build/dist/Server/API/UserCallAPI.js +42 -38
  215. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  216. package/build/dist/Server/API/UserEmailAPI.js +42 -38
  217. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  218. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +37 -32
  219. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
  220. package/build/dist/Server/API/UserNotificationMethodAdminAPI.js +341 -0
  221. package/build/dist/Server/API/UserNotificationMethodAdminAPI.js.map +1 -0
  222. package/build/dist/Server/API/UserPushAPI.js +95 -2
  223. package/build/dist/Server/API/UserPushAPI.js.map +1 -1
  224. package/build/dist/Server/API/UserSmsAPI.js +42 -38
  225. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  226. package/build/dist/Server/API/UserWhatsAppAPI.js +42 -40
  227. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  228. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js +89 -0
  229. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js.map +1 -0
  230. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js +12 -0
  231. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js.map +1 -0
  232. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js +40 -0
  233. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js.map +1 -0
  234. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  236. package/build/dist/Server/Middleware/VerificationCodeRateLimit.js +393 -0
  237. package/build/dist/Server/Middleware/VerificationCodeRateLimit.js.map +1 -0
  238. package/build/dist/Server/Services/AnalyticsDatabaseService.js +136 -0
  239. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  240. package/build/dist/Server/Services/DatabaseService.js +74 -0
  241. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  242. package/build/dist/Server/Services/LogAggregationService.js +5 -0
  243. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  244. package/build/dist/Server/Services/PushNotificationService.js +69 -30
  245. package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
  246. package/build/dist/Server/Services/TeamMemberService.js +43 -7
  247. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  248. package/build/dist/Server/Services/UserCallService.js +54 -22
  249. package/build/dist/Server/Services/UserCallService.js.map +1 -1
  250. package/build/dist/Server/Services/UserEmailService.js +78 -17
  251. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  252. package/build/dist/Server/Services/UserIncomingCallNumberService.js +45 -74
  253. package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -1
  254. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1117 -0
  255. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -0
  256. package/build/dist/Server/Services/UserNotificationRuleService.js +20 -0
  257. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  258. package/build/dist/Server/Services/UserPushService.js +77 -0
  259. package/build/dist/Server/Services/UserPushService.js.map +1 -1
  260. package/build/dist/Server/Services/UserSmsService.js +50 -17
  261. package/build/dist/Server/Services/UserSmsService.js.map +1 -1
  262. package/build/dist/Server/Services/UserWhatsAppService.js +48 -15
  263. package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
  264. package/build/dist/Server/Types/Database/QueryHelper.js +27 -0
  265. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  266. package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js +46 -0
  267. package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js.map +1 -1
  268. package/build/dist/Server/Utils/ChannelVerification.js +348 -0
  269. package/build/dist/Server/Utils/ChannelVerification.js.map +1 -0
  270. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +13 -12
  271. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  272. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +20 -17
  273. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  274. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +17 -14
  275. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  276. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +95 -0
  277. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -0
  278. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +313 -0
  279. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -0
  280. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +3 -3
  281. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +67 -26
  282. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
  283. package/build/dist/Server/Utils/TotpAuth.js +127 -8
  284. package/build/dist/Server/Utils/TotpAuth.js.map +1 -1
  285. package/build/dist/Server/Utils/UserRegistrationToken.js +170 -0
  286. package/build/dist/Server/Utils/UserRegistrationToken.js.map +1 -0
  287. package/build/dist/Server/Utils/VerificationCode.js +120 -0
  288. package/build/dist/Server/Utils/VerificationCode.js.map +1 -0
  289. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  290. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  291. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +42 -21
  292. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  293. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +77 -5
  294. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  295. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +18 -6
  296. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  297. package/build/dist/Types/Monitor/ServiceAlertTemplates.js +1028 -0
  298. package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -0
  299. package/build/dist/Types/Permission.js +33 -0
  300. package/build/dist/Types/Permission.js.map +1 -1
  301. package/build/dist/Types/PushNotification/AndroidNotificationChannel.js +27 -0
  302. package/build/dist/Types/PushNotification/AndroidNotificationChannel.js.map +1 -0
  303. package/build/dist/Types/Service/ServiceLanguage.js +96 -0
  304. package/build/dist/Types/Service/ServiceLanguage.js.map +1 -0
  305. package/build/dist/Types/Text.js +82 -17
  306. package/build/dist/Types/Text.js.map +1 -1
  307. package/build/dist/UI/Components/Button/Button.js +22 -14
  308. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  309. package/build/dist/UI/Components/CodeBlock/CodeBlock.js +35 -3
  310. package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
  311. package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js +57 -0
  312. package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js.map +1 -0
  313. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +439 -0
  314. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -0
  315. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js +135 -0
  316. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js.map +1 -0
  317. package/build/dist/UI/Components/CommandPalette/PaletteRow.js +83 -0
  318. package/build/dist/UI/Components/CommandPalette/PaletteRow.js.map +1 -0
  319. package/build/dist/UI/Components/CommandPalette/RecentCommands.js +47 -0
  320. package/build/dist/UI/Components/CommandPalette/RecentCommands.js.map +1 -0
  321. package/build/dist/UI/Components/CommandPalette/Types.js +2 -0
  322. package/build/dist/UI/Components/CommandPalette/Types.js.map +1 -0
  323. package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js +88 -0
  324. package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js.map +1 -0
  325. package/build/dist/UI/Components/Dropdown/Dropdown.js +6 -1
  326. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  327. package/build/dist/UI/Components/Feed/FeedItem.js +1 -1
  328. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  329. package/build/dist/UI/Components/List/List.js +19 -5
  330. package/build/dist/UI/Components/List/List.js.map +1 -1
  331. package/build/dist/UI/Components/List/ListSkeleton.js +21 -0
  332. package/build/dist/UI/Components/List/ListSkeleton.js.map +1 -0
  333. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
  334. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +52 -25
  335. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  336. package/build/dist/UI/Components/Modal/Modal.js +2 -2
  337. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  338. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  339. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +9 -2
  340. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
  341. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +32 -1
  342. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  343. package/build/dist/UI/Components/Navbar/NavBar.js +5 -1
  344. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  345. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +29 -5
  346. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
  347. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +23 -1
  348. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
  349. package/build/dist/UI/Components/SideOver/SideOver.js +23 -2
  350. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  351. package/build/dist/UI/Components/Skeleton/Skeleton.js +23 -0
  352. package/build/dist/UI/Components/Skeleton/Skeleton.js.map +1 -0
  353. package/build/dist/UI/Components/Table/Table.js +35 -24
  354. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  355. package/build/dist/UI/Components/Table/TableSkeletonRows.js +52 -0
  356. package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -0
  357. package/build/dist/UI/Components/Tabs/Tab.js +1 -1
  358. package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
  359. package/build/dist/UI/Components/Toast/Toast.js +77 -23
  360. package/build/dist/UI/Components/Toast/Toast.js.map +1 -1
  361. package/build/dist/UI/Components/Toast/ToastInit.js +37 -15
  362. package/build/dist/UI/Components/Toast/ToastInit.js.map +1 -1
  363. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -9
  364. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  365. package/build/dist/UI/Utils/ModelListCache.js +126 -0
  366. package/build/dist/UI/Utils/ModelListCache.js.map +1 -0
  367. package/build/dist/UI/Utils/Project.js +24 -1
  368. package/build/dist/UI/Utils/Project.js.map +1 -1
  369. package/build/dist/Utils/API.js +6 -1
  370. package/build/dist/Utils/API.js.map +1 -1
  371. package/jest.config.json +1 -1
  372. package/package.json +2 -3
  373. package/Server/Utils/Monitor/MonitorClusterContext.ts +0 -182
  374. package/Tests/__mocks__/otpauth.js +0 -30
  375. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +0 -141
  376. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +0 -1
@@ -0,0 +1,458 @@
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 PushNotificationService from "../../../Server/Services/PushNotificationService";
10
+ import logger from "../../../Server/Utils/Logger";
11
+ import Incident from "../../../Models/DatabaseModels/Incident";
12
+ import Alert from "../../../Models/DatabaseModels/Alert";
13
+ import AlertEpisode from "../../../Models/DatabaseModels/AlertEpisode";
14
+ import IncidentEpisode from "../../../Models/DatabaseModels/IncidentEpisode";
15
+ import UserNotificationRule from "../../../Models/DatabaseModels/UserNotificationRule";
16
+ import UserPush from "../../../Models/DatabaseModels/UserPush";
17
+ import PushNotificationRequest from "../../../Types/PushNotification/PushNotificationRequest";
18
+ import ObjectID from "../../../Types/ObjectID";
19
+ import URL from "../../../Types/API/URL";
20
+ import { JSONObject } from "../../../Types/JSON";
21
+ import NotificationRuleType from "../../../Types/NotificationRule/NotificationRuleType";
22
+ import PushDeviceType from "../../../Types/PushNotification/PushDeviceType";
23
+ import UserNotificationEventType from "../../../Types/UserNotification/UserNotificationEventType";
24
+ import { describe, expect, test, beforeEach, afterEach } from "@jest/globals";
25
+
26
+ /*
27
+ * The on-call paging path is the ONLY place in the product allowed to send a
28
+ * notification that overrides a silenced phone, and it may only do so for a
29
+ * device whose owner turned the option on. Both halves of that sentence are
30
+ * load-bearing and neither fails loudly:
31
+ *
32
+ * - a page that loses the flag arrives silently, and the responder sleeps
33
+ * through the incident. Nothing logs an error; the page was "delivered".
34
+ * - a page that gains the flag it should not have wakes somebody who asked
35
+ * not to be woken, which is how an on-call app gets its notifications
36
+ * switched off entirely.
37
+ *
38
+ * So this file drives the real delivery half with a real UserPush model and
39
+ * inspects what was actually handed to the sender, for every event type that
40
+ * pages a responder.
41
+ */
42
+
43
+ const PROJECT_ID: ObjectID = new ObjectID(
44
+ "11111111-1111-4111-8111-111111111111",
45
+ );
46
+ const LOG_ID: ObjectID = new ObjectID("22222222-2222-4222-8222-222222222222");
47
+ const RULE_ID: ObjectID = new ObjectID("33333333-3333-4333-8333-333333333333");
48
+ const USER_ID: ObjectID = new ObjectID("44444444-4444-4444-8444-444444444444");
49
+ const INCIDENT_ID: ObjectID = new ObjectID(
50
+ "55555555-5555-4555-8555-555555555555",
51
+ );
52
+ const ALERT_ID: ObjectID = new ObjectID("66666666-6666-4666-8666-666666666666");
53
+ const ALERT_EPISODE_ID: ObjectID = new ObjectID(
54
+ "77777777-7777-4777-8777-777777777777",
55
+ );
56
+ const INCIDENT_EPISODE_ID: ObjectID = new ObjectID(
57
+ "88888888-8888-4888-8888-888888888888",
58
+ );
59
+ const TIMELINE_ID: ObjectID = new ObjectID(
60
+ "99999999-9999-4999-8999-999999999999",
61
+ );
62
+ const PUSH_METHOD_ID: ObjectID = new ObjectID(
63
+ "dddddddd-dddd-4ddd-8ddd-dddddddddddd",
64
+ );
65
+
66
+ const DEVICE_TOKEN: string = "ExponentPushToken[test-device]";
67
+
68
+ type ExecuteOptions = Parameters<
69
+ typeof UserNotificationRuleService.executeNotificationRuleItem
70
+ >[1];
71
+
72
+ /*
73
+ * deliverNotificationForRule is private, so TypeScript will not let a test name
74
+ * it. It is an ordinary prototype method at runtime and the on-call fallback
75
+ * already calls it with an unsaved rule, so it is reached through a structural
76
+ * cast - the same approach the neighbouring test files use.
77
+ */
78
+ interface DeliveryHalf {
79
+ deliverNotificationForRule: (
80
+ notificationRuleItem: UserNotificationRule,
81
+ options: ExecuteOptions,
82
+ ) => Promise<boolean>;
83
+ }
84
+
85
+ function deliveryHalf(): DeliveryHalf {
86
+ return UserNotificationRuleService as unknown as DeliveryHalf;
87
+ }
88
+
89
+ function userPushDevice(options: {
90
+ isCriticalAlertEnabled?: boolean;
91
+ deviceType?: PushDeviceType;
92
+ }): UserPush {
93
+ const userPush: UserPush = new UserPush();
94
+ userPush._id = PUSH_METHOD_ID.toString();
95
+ userPush.deviceToken = DEVICE_TOKEN;
96
+ userPush.deviceType = options.deviceType ?? PushDeviceType.iOS;
97
+ userPush.isVerified = true;
98
+ userPush.userId = USER_ID;
99
+
100
+ if (options.isCriticalAlertEnabled !== undefined) {
101
+ userPush.isCriticalAlertEnabled = options.isCriticalAlertEnabled;
102
+ }
103
+
104
+ return userPush;
105
+ }
106
+
107
+ function pushOnlyRule(device: UserPush): UserNotificationRule {
108
+ const rule: UserNotificationRule = new UserNotificationRule();
109
+ rule.projectId = PROJECT_ID;
110
+ rule.userId = USER_ID;
111
+ rule.ruleType = NotificationRuleType.ON_CALL_EXECUTED_INCIDENT;
112
+ rule.notifyAfterMinutes = 0;
113
+ rule.userPush = device;
114
+ rule.userPushId = PUSH_METHOD_ID;
115
+
116
+ return rule;
117
+ }
118
+
119
+ /*
120
+ * The delivery half loads the thing being paged about from whichever
121
+ * triggeredBy* id matches the event type, and refuses outright if none of them
122
+ * resolves. So the id has to travel with the event type rather than being set
123
+ * once - a mismatch here fails as "Incident, Alert, Alert Episode, or Incident
124
+ * Episode not found", a long way from the pairing that caused it.
125
+ */
126
+ const TRIGGER_ID_FOR_EVENT: Record<string, Partial<ExecuteOptions>> = {
127
+ [UserNotificationEventType.IncidentCreated]: {
128
+ triggeredByIncidentId: INCIDENT_ID,
129
+ },
130
+ [UserNotificationEventType.AlertCreated]: {
131
+ triggeredByAlertId: ALERT_ID,
132
+ },
133
+ [UserNotificationEventType.AlertEpisodeCreated]: {
134
+ triggeredByAlertEpisodeId: ALERT_EPISODE_ID,
135
+ },
136
+ [UserNotificationEventType.IncidentEpisodeCreated]: {
137
+ triggeredByIncidentEpisodeId: INCIDENT_EPISODE_ID,
138
+ },
139
+ };
140
+
141
+ function executeOptions(
142
+ overrides: Partial<ExecuteOptions> = {},
143
+ ): ExecuteOptions {
144
+ const eventType: UserNotificationEventType =
145
+ (overrides as { userNotificationEventType?: UserNotificationEventType })
146
+ .userNotificationEventType ?? UserNotificationEventType.IncidentCreated;
147
+
148
+ return {
149
+ projectId: PROJECT_ID,
150
+ userNotificationEventType: eventType,
151
+ userNotificationLogId: LOG_ID,
152
+ ...TRIGGER_ID_FOR_EVENT[eventType],
153
+ ...overrides,
154
+ } as ExecuteOptions;
155
+ }
156
+
157
+ function fakeIncident(): Incident {
158
+ return {
159
+ id: INCIDENT_ID,
160
+ projectId: PROJECT_ID,
161
+ title: "Checkout is down",
162
+ incidentNumber: 42,
163
+ incidentNumberWithPrefix: "INC-42",
164
+ } as unknown as Incident;
165
+ }
166
+
167
+ function fakeAlert(): Alert {
168
+ return {
169
+ id: ALERT_ID,
170
+ projectId: PROJECT_ID,
171
+ title: "Disk almost full",
172
+ alertNumber: 7,
173
+ alertNumberWithPrefix: "ALT-7",
174
+ } as unknown as Alert;
175
+ }
176
+
177
+ function fakeAlertEpisode(): AlertEpisode {
178
+ return {
179
+ id: ALERT_EPISODE_ID,
180
+ projectId: PROJECT_ID,
181
+ title: "Disk pressure across the fleet",
182
+ episodeNumber: 3,
183
+ } as unknown as AlertEpisode;
184
+ }
185
+
186
+ function fakeIncidentEpisode(): IncidentEpisode {
187
+ return {
188
+ id: INCIDENT_EPISODE_ID,
189
+ projectId: PROJECT_ID,
190
+ title: "Payments degraded",
191
+ episodeNumber: 4,
192
+ } as unknown as IncidentEpisode;
193
+ }
194
+
195
+ describe("On-call push notifications and the critical alert flag", () => {
196
+ let pushSpy: jest.SpyInstance;
197
+
198
+ beforeEach(() => {
199
+ jest.spyOn(logger, "error").mockImplementation((): void => {
200
+ return undefined;
201
+ });
202
+ jest.spyOn(logger, "warn").mockImplementation((): void => {
203
+ return undefined;
204
+ });
205
+ jest.spyOn(logger, "info").mockImplementation((): void => {
206
+ return undefined;
207
+ });
208
+
209
+ jest
210
+ .spyOn(UserOnCallLogService, "claimNotificationRuleExecution")
211
+ .mockResolvedValue(true as never);
212
+
213
+ jest
214
+ .spyOn(UserOnCallLogTimelineService, "create")
215
+ .mockResolvedValue({ id: TIMELINE_ID } as unknown as never);
216
+
217
+ jest
218
+ .spyOn(UserOnCallLogTimelineService, "updateOneById")
219
+ .mockResolvedValue(undefined as never);
220
+
221
+ jest
222
+ .spyOn(ProjectCallSMSConfigService, "getProjectDefaultTwilioConfig")
223
+ .mockResolvedValue(undefined as never);
224
+
225
+ jest
226
+ .spyOn(IncidentService, "findOneById")
227
+ .mockResolvedValue(fakeIncident() as never);
228
+ jest
229
+ .spyOn(IncidentService, "getIncidentLinkInDashboard")
230
+ .mockResolvedValue(
231
+ URL.fromString("https://dashboard.example.com/incident") as never,
232
+ );
233
+
234
+ jest
235
+ .spyOn(AlertService, "findOneById")
236
+ .mockResolvedValue(fakeAlert() as never);
237
+ jest
238
+ .spyOn(AlertService, "getAlertLinkInDashboard")
239
+ .mockResolvedValue(
240
+ URL.fromString("https://dashboard.example.com/alert") as never,
241
+ );
242
+
243
+ jest
244
+ .spyOn(AlertEpisodeService, "findOneById")
245
+ .mockResolvedValue(fakeAlertEpisode() as never);
246
+ jest
247
+ .spyOn(IncidentEpisodeService, "findOneById")
248
+ .mockResolvedValue(fakeIncidentEpisode() as never);
249
+
250
+ pushSpy = jest
251
+ .spyOn(PushNotificationService, "sendPushNotification")
252
+ .mockResolvedValue(undefined as never);
253
+ });
254
+
255
+ afterEach(() => {
256
+ jest.restoreAllMocks();
257
+ });
258
+
259
+ function sentRequest(): PushNotificationRequest {
260
+ expect(pushSpy).toHaveBeenCalledTimes(1);
261
+ return pushSpy.mock.calls[0]![0] as PushNotificationRequest;
262
+ }
263
+
264
+ const pagingEvents: Array<[string, UserNotificationEventType]> = [
265
+ ["an incident", UserNotificationEventType.IncidentCreated],
266
+ ["an alert", UserNotificationEventType.AlertCreated],
267
+ ["an alert episode", UserNotificationEventType.AlertEpisodeCreated],
268
+ ["an incident episode", UserNotificationEventType.IncidentEpisodeCreated],
269
+ ];
270
+
271
+ describe("a device that opted in is paged as a critical alert", () => {
272
+ test.each(pagingEvents)(
273
+ "%s page overrides silent mode",
274
+ async (_label: string, eventType: UserNotificationEventType) => {
275
+ const rule: UserNotificationRule = pushOnlyRule(
276
+ userPushDevice({ isCriticalAlertEnabled: true }),
277
+ );
278
+
279
+ await deliveryHalf().deliverNotificationForRule(
280
+ rule,
281
+ executeOptions({ userNotificationEventType: eventType }),
282
+ );
283
+
284
+ expect(sentRequest().message.isCriticalAlert).toBe(true);
285
+ },
286
+ );
287
+ });
288
+
289
+ describe("a device that did not opt in is paged normally", () => {
290
+ test.each(pagingEvents)(
291
+ "%s page respects the ringer switch when the flag is false",
292
+ async (_label: string, eventType: UserNotificationEventType) => {
293
+ const rule: UserNotificationRule = pushOnlyRule(
294
+ userPushDevice({ isCriticalAlertEnabled: false }),
295
+ );
296
+
297
+ await deliveryHalf().deliverNotificationForRule(
298
+ rule,
299
+ executeOptions({ userNotificationEventType: eventType }),
300
+ );
301
+
302
+ expect(sentRequest().message.isCriticalAlert).toBe(false);
303
+ },
304
+ );
305
+
306
+ test.each(pagingEvents)(
307
+ "%s page respects the ringer switch when the column was never set",
308
+ async (_label: string, eventType: UserNotificationEventType) => {
309
+ /*
310
+ * Every device registered before this feature shipped reads back as
311
+ * undefined until the migration's default is loaded. Undefined must
312
+ * behave as "off" rather than as "unknown, escalate anyway".
313
+ */
314
+ const rule: UserNotificationRule = pushOnlyRule(userPushDevice({}));
315
+
316
+ await deliveryHalf().deliverNotificationForRule(
317
+ rule,
318
+ executeOptions({ userNotificationEventType: eventType }),
319
+ );
320
+
321
+ expect(sentRequest().message.isCriticalAlert).toBe(false);
322
+ },
323
+ );
324
+ });
325
+
326
+ describe("the flag travels with the page, not instead of it", () => {
327
+ test("the page still carries its title, body and device", async () => {
328
+ const rule: UserNotificationRule = pushOnlyRule(
329
+ userPushDevice({ isCriticalAlertEnabled: true }),
330
+ );
331
+
332
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
333
+
334
+ const request: PushNotificationRequest = sentRequest();
335
+
336
+ expect(request.devices).toEqual([{ token: DEVICE_TOKEN }]);
337
+ expect(request.deviceType).toBe(PushDeviceType.iOS);
338
+ expect(request.message.title).toContain("Checkout is down");
339
+ expect(request.message.body.length).toBeGreaterThan(0);
340
+ });
341
+
342
+ test("an Android device gets the flag too", async () => {
343
+ const rule: UserNotificationRule = pushOnlyRule(
344
+ userPushDevice({
345
+ isCriticalAlertEnabled: true,
346
+ deviceType: PushDeviceType.Android,
347
+ }),
348
+ );
349
+
350
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
351
+
352
+ const request: PushNotificationRequest = sentRequest();
353
+
354
+ expect(request.deviceType).toBe(PushDeviceType.Android);
355
+ expect(request.message.isCriticalAlert).toBe(true);
356
+ });
357
+
358
+ test("the on-call log timeline still records the push attempt", async () => {
359
+ const rule: UserNotificationRule = pushOnlyRule(
360
+ userPushDevice({ isCriticalAlertEnabled: true }),
361
+ );
362
+
363
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
364
+
365
+ expect(UserOnCallLogTimelineService.create).toHaveBeenCalled();
366
+ });
367
+ });
368
+
369
+ describe("an unverified device is not paged at all", () => {
370
+ test("opting into critical alerts does not bypass verification", async () => {
371
+ /*
372
+ * The critical flag decides HOW a page sounds, never WHETHER it is sent.
373
+ * A device that was never verified must stay silent regardless.
374
+ */
375
+ const device: UserPush = userPushDevice({
376
+ isCriticalAlertEnabled: true,
377
+ });
378
+ device.isVerified = false;
379
+
380
+ const rule: UserNotificationRule = pushOnlyRule(device);
381
+
382
+ await deliveryHalf().deliverNotificationForRule(rule, executeOptions());
383
+
384
+ expect(pushSpy).not.toHaveBeenCalled();
385
+ });
386
+ });
387
+ });
388
+
389
+ describe("The rule select loads the critical alert flag", () => {
390
+ /*
391
+ * An unselected column arrives as undefined, which the delivery half reads
392
+ * as "not opted in". So dropping this field from the select does not error -
393
+ * it silently downgrades every critical page in the product to a normal one.
394
+ * That is a one-line change with no visible symptom until somebody sleeps
395
+ * through an incident, which is exactly the kind of regression a test has to
396
+ * hold.
397
+ */
398
+ let findSpy: jest.SpyInstance;
399
+
400
+ beforeEach(() => {
401
+ jest.spyOn(logger, "error").mockImplementation((): void => {
402
+ return undefined;
403
+ });
404
+
405
+ jest
406
+ .spyOn(UserOnCallLogService, "claimNotificationRuleExecution")
407
+ .mockResolvedValue(true as never);
408
+
409
+ jest
410
+ .spyOn(deliveryHalf(), "deliverNotificationForRule")
411
+ .mockResolvedValue(true as never);
412
+
413
+ findSpy = jest
414
+ .spyOn(UserNotificationRuleService, "findOneById")
415
+ .mockResolvedValue({
416
+ id: RULE_ID,
417
+ _id: RULE_ID.toString(),
418
+ userId: USER_ID,
419
+ } as unknown as never);
420
+ });
421
+
422
+ afterEach(() => {
423
+ jest.restoreAllMocks();
424
+ });
425
+
426
+ test("userPush.isCriticalAlertEnabled is selected", async () => {
427
+ await UserNotificationRuleService.executeNotificationRuleItem(
428
+ RULE_ID,
429
+ executeOptions(),
430
+ );
431
+
432
+ const select: JSONObject = (
433
+ findSpy.mock.calls[0]![0] as { select: JSONObject }
434
+ ).select;
435
+
436
+ const userPushSelect: JSONObject = select["userPush"] as JSONObject;
437
+
438
+ expect(userPushSelect["isCriticalAlertEnabled"]).toBe(true);
439
+ });
440
+
441
+ test("the columns the push branch already depended on are still selected", async () => {
442
+ await UserNotificationRuleService.executeNotificationRuleItem(
443
+ RULE_ID,
444
+ executeOptions(),
445
+ );
446
+
447
+ const select: JSONObject = (
448
+ findSpy.mock.calls[0]![0] as { select: JSONObject }
449
+ ).select;
450
+
451
+ const userPushSelect: JSONObject = select["userPush"] as JSONObject;
452
+
453
+ expect(userPushSelect["deviceToken"]).toBe(true);
454
+ expect(userPushSelect["deviceType"]).toBe(true);
455
+ expect(userPushSelect["isVerified"]).toBe(true);
456
+ expect(userPushSelect["userId"]).toBe(true);
457
+ });
458
+ });