@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,690 @@
1
+ import Monitor from "../../../../Models/DatabaseModels/Monitor";
2
+ import MonitorStepResourceIdentity from "../../../../Server/Utils/Monitor/MonitorStepResourceIdentity";
3
+ import { SeriesResourceRefs } from "../../../../Server/Utils/Monitor/SeriesResourceLabels";
4
+ import { JSONObject } from "../../../../Types/JSON";
5
+ import MonitorStep from "../../../../Types/Monitor/MonitorStep";
6
+ import MonitorSteps from "../../../../Types/Monitor/MonitorSteps";
7
+ import MonitorType from "../../../../Types/Monitor/MonitorType";
8
+ import ObjectID from "../../../../Types/ObjectID";
9
+ import { describe, expect, test } from "@jest/globals";
10
+
11
+ /*
12
+ * MonitorStepResourceIdentity reads the resources a monitor's own
13
+ * configuration names, so an alert or incident can be attached to them
14
+ * even when the criteria is ungrouped and emits no series labels.
15
+ *
16
+ * The regression that motivated it: a metric monitor scoped to one
17
+ * service with the attribute filter
18
+ * `oneuptime.service.name = app-plan-starship-online-production` opened
19
+ * alerts whose "Affected Resources" card read "No resources affected" —
20
+ * the filter named the service, but nothing ever read it.
21
+ *
22
+ * Pure module: no database, no mocks.
23
+ */
24
+
25
+ const SERVICE_ID_A: string = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
26
+ const SERVICE_ID_B: string = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
27
+
28
+ function monitorWithSteps(
29
+ monitorType: MonitorType,
30
+ stepDataList: Array<JSONObject>,
31
+ ): Monitor {
32
+ const model: Monitor = new Monitor();
33
+ model.monitorType = monitorType;
34
+ model.projectId = new ObjectID("11111111-1111-4111-8111-111111111111");
35
+
36
+ const steps: MonitorSteps = new MonitorSteps();
37
+ steps.data = {
38
+ monitorStepsInstanceArray: stepDataList.map(
39
+ (stepData: JSONObject): MonitorStep => {
40
+ const step: MonitorStep = new MonitorStep();
41
+ step.data = {
42
+ ...step.data,
43
+ ...stepData,
44
+ } as MonitorStep["data"];
45
+ return step;
46
+ },
47
+ ),
48
+ };
49
+
50
+ model.monitorSteps = steps;
51
+ return model;
52
+ }
53
+
54
+ /*
55
+ * A metric view config carrying one query whose filter attributes are
56
+ * exactly `attributes`. This is the shape every metric-backed monitor
57
+ * step holds, and the shape the user's reported bug lives in.
58
+ */
59
+ function metricViewConfigWith(attributes: JSONObject): JSONObject {
60
+ return {
61
+ queryConfigs: [
62
+ {
63
+ metricQueryData: {
64
+ filterData: {
65
+ metricName: "azure_memorypercentage_maximum",
66
+ attributes: attributes,
67
+ },
68
+ },
69
+ },
70
+ ],
71
+ formulaConfigs: [],
72
+ };
73
+ }
74
+
75
+ function refsFor(monitor: Monitor): SeriesResourceRefs {
76
+ return MonitorStepResourceIdentity.extractResourceRefsFromMonitor({
77
+ monitor: monitor,
78
+ });
79
+ }
80
+
81
+ describe("MonitorStepResourceIdentity — the reported bug", () => {
82
+ test("a metric monitor filtered by oneuptime.service.name names that service", () => {
83
+ /*
84
+ * ALT-144 in the wild: a Metrics monitor whose only resource
85
+ * identity is an attribute filter. It is ungrouped, so the series
86
+ * path sees nothing; this is the only thing that can name the
87
+ * service.
88
+ */
89
+ const refs: SeriesResourceRefs = refsFor(
90
+ monitorWithSteps(MonitorType.Metrics, [
91
+ {
92
+ metricMonitor: {
93
+ metricViewConfig: metricViewConfigWith({
94
+ "oneuptime.service.name": "app-plan-starship-online-production",
95
+ }),
96
+ },
97
+ },
98
+ ]),
99
+ );
100
+
101
+ expect(refs.serviceNames).toEqual(["app-plan-starship-online-production"]);
102
+ });
103
+
104
+ test("every accepted service-name spelling resolves", () => {
105
+ for (const key of [
106
+ "service.name",
107
+ "resource.service.name",
108
+ "oneuptime.service.name",
109
+ "resource.oneuptime.service.name",
110
+ ]) {
111
+ const refs: SeriesResourceRefs = refsFor(
112
+ monitorWithSteps(MonitorType.Metrics, [
113
+ {
114
+ metricMonitor: {
115
+ metricViewConfig: metricViewConfigWith({ [key]: "checkout-api" }),
116
+ },
117
+ },
118
+ ]),
119
+ );
120
+
121
+ expect(refs.serviceNames).toEqual(["checkout-api"]);
122
+ }
123
+ });
124
+
125
+ test("a non-identifying filter attribute names nothing", () => {
126
+ const refs: SeriesResourceRefs = refsFor(
127
+ monitorWithSteps(MonitorType.Metrics, [
128
+ {
129
+ metricMonitor: {
130
+ metricViewConfig: metricViewConfigWith({
131
+ "http.response.status_code": "500",
132
+ }),
133
+ },
134
+ },
135
+ ]),
136
+ );
137
+
138
+ expect(MonitorStepResourceIdentity.isEmpty(refs)).toBe(true);
139
+ });
140
+
141
+ test("a non-string filter (Search / Includes) names nothing", () => {
142
+ /*
143
+ * `service.name CONTAINS prod` matches a set, not one row. Treating
144
+ * the operator object as a name would stringify to "[object Object]"
145
+ * and look up a service that cannot exist.
146
+ */
147
+ const refs: SeriesResourceRefs = refsFor(
148
+ monitorWithSteps(MonitorType.Metrics, [
149
+ {
150
+ metricMonitor: {
151
+ metricViewConfig: metricViewConfigWith({
152
+ "service.name": { _type: "Search", value: "prod" },
153
+ }),
154
+ },
155
+ },
156
+ ]),
157
+ );
158
+
159
+ expect(refs.serviceNames).toEqual([]);
160
+ });
161
+ });
162
+
163
+ describe("MonitorStepResourceIdentity — telemetry service ids", () => {
164
+ test.each([
165
+ ["logMonitor", MonitorType.Logs],
166
+ ["traceMonitor", MonitorType.Traces],
167
+ ["exceptionMonitor", MonitorType.Exceptions],
168
+ /*
169
+ * Profiles has no metricViewConfig and no declared identifier, so
170
+ * telemetryServiceIds is the ONLY identity a profile monitor has —
171
+ * omitting it here leaves that type with the original bug.
172
+ */
173
+ ["profileMonitor", MonitorType.Profiles],
174
+ ["metricMonitor", MonitorType.Metrics],
175
+ ])(
176
+ "%s.telemetryServiceIds names its services",
177
+ (stepKey: string, monitorType: MonitorType) => {
178
+ const refs: SeriesResourceRefs = refsFor(
179
+ monitorWithSteps(monitorType, [
180
+ {
181
+ [stepKey]: {
182
+ telemetryServiceIds: [
183
+ new ObjectID(SERVICE_ID_A),
184
+ new ObjectID(SERVICE_ID_B),
185
+ ],
186
+ },
187
+ },
188
+ ]),
189
+ );
190
+
191
+ expect(refs.serviceIds.sort()).toEqual(
192
+ [SERVICE_ID_A, SERVICE_ID_B].sort(),
193
+ );
194
+ },
195
+ );
196
+
197
+ test("a service id persisted as a bare string still resolves", () => {
198
+ /*
199
+ * Step JSON is not schema-checked, so an id can arrive as a plain
200
+ * string rather than a rehydrated ObjectID.
201
+ */
202
+ const refs: SeriesResourceRefs = refsFor(
203
+ monitorWithSteps(MonitorType.Logs, [
204
+ { logMonitor: { telemetryServiceIds: [SERVICE_ID_A] } },
205
+ ]),
206
+ );
207
+
208
+ expect(refs.serviceIds).toEqual([SERVICE_ID_A]);
209
+ });
210
+
211
+ test("an empty telemetryServiceIds list names nothing", () => {
212
+ const refs: SeriesResourceRefs = refsFor(
213
+ monitorWithSteps(MonitorType.Logs, [
214
+ { logMonitor: { telemetryServiceIds: [] } },
215
+ ]),
216
+ );
217
+
218
+ expect(MonitorStepResourceIdentity.isEmpty(refs)).toBe(true);
219
+ });
220
+ });
221
+
222
+ describe("MonitorStepResourceIdentity — declared infra identifiers", () => {
223
+ test.each([
224
+ [MonitorType.Host, "hostMonitor", "hostIdentifier", "hostNames"],
225
+ [MonitorType.Docker, "dockerMonitor", "hostIdentifier", "dockerHostNames"],
226
+ [MonitorType.Podman, "podmanMonitor", "hostIdentifier", "podmanHostNames"],
227
+ [
228
+ MonitorType.Kubernetes,
229
+ "kubernetesMonitor",
230
+ "clusterIdentifier",
231
+ "kubernetesClusterNames",
232
+ ],
233
+ [
234
+ MonitorType.Proxmox,
235
+ "proxmoxMonitor",
236
+ "clusterIdentifier",
237
+ "proxmoxClusterNames",
238
+ ],
239
+ [MonitorType.Ceph, "cephMonitor", "clusterIdentifier", "cephClusterNames"],
240
+ [
241
+ MonitorType.DockerSwarm,
242
+ "dockerSwarmMonitor",
243
+ "clusterIdentifier",
244
+ "dockerSwarmClusterNames",
245
+ ],
246
+ [MonitorType.IoTDevice, "iotMonitor", "fleetIdentifier", "iotFleetNames"],
247
+ ])(
248
+ "a %s monitor names its resource via %s.%s",
249
+ (
250
+ monitorType: MonitorType,
251
+ stepKey: string,
252
+ identifierKey: string,
253
+ refKey: string,
254
+ ) => {
255
+ const refs: SeriesResourceRefs = refsFor(
256
+ monitorWithSteps(monitorType, [
257
+ { [stepKey]: { [identifierKey]: "prod-01" } },
258
+ ]),
259
+ );
260
+
261
+ expect(refs[refKey as keyof SeriesResourceRefs]).toEqual(["prod-01"]);
262
+
263
+ /*
264
+ * The identifier must land in exactly one bucket. A Docker
265
+ * monitor that also produced `hostNames` would attach an
266
+ * unrelated Host row.
267
+ */
268
+ const populated: Array<string> = Object.entries(refs)
269
+ .filter(([, values]: [string, Array<string>]): boolean => {
270
+ return values.length > 0;
271
+ })
272
+ .map(([key]: [string, Array<string>]): string => {
273
+ return key;
274
+ });
275
+
276
+ expect(populated).toEqual([refKey]);
277
+ },
278
+ );
279
+
280
+ test("a blank identifier names nothing", () => {
281
+ const refs: SeriesResourceRefs = refsFor(
282
+ monitorWithSteps(MonitorType.Host, [
283
+ { hostMonitor: { hostIdentifier: " " } },
284
+ ]),
285
+ );
286
+
287
+ expect(MonitorStepResourceIdentity.isEmpty(refs)).toBe(true);
288
+ });
289
+
290
+ test("an identifier is trimmed", () => {
291
+ const refs: SeriesResourceRefs = refsFor(
292
+ monitorWithSteps(MonitorType.Host, [
293
+ { hostMonitor: { hostIdentifier: " prod-01 " } },
294
+ ]),
295
+ );
296
+
297
+ expect(refs.hostNames).toEqual(["prod-01"]);
298
+ });
299
+ });
300
+
301
+ describe("MonitorStepResourceIdentity — Docker / Podman host disambiguation", () => {
302
+ test("a Docker monitor's resource.host.name filter does NOT name a Host", () => {
303
+ /*
304
+ * The Docker worker writes the step's hostIdentifier into
305
+ * `resource.host.name`, which the label key map hands to Host. That
306
+ * value names a DockerHost row. Honouring the map would attach an
307
+ * unrelated Host and surface the alert on that host's Activity tab.
308
+ */
309
+ const refs: SeriesResourceRefs = refsFor(
310
+ monitorWithSteps(MonitorType.Docker, [
311
+ {
312
+ dockerMonitor: {
313
+ hostIdentifier: "docker-prod-01",
314
+ metricViewConfig: metricViewConfigWith({
315
+ "resource.host.name": "docker-prod-01",
316
+ }),
317
+ },
318
+ },
319
+ ]),
320
+ );
321
+
322
+ expect(refs.hostNames).toEqual([]);
323
+ expect(refs.hostIds).toEqual([]);
324
+ expect(refs.dockerHostNames).toEqual(["docker-prod-01"]);
325
+ });
326
+
327
+ test("a Podman monitor's resource.host.name filter does NOT name a Host", () => {
328
+ const refs: SeriesResourceRefs = refsFor(
329
+ monitorWithSteps(MonitorType.Podman, [
330
+ {
331
+ podmanMonitor: {
332
+ hostIdentifier: "podman-prod-01",
333
+ metricViewConfig: metricViewConfigWith({
334
+ "resource.host.name": "podman-prod-01",
335
+ }),
336
+ },
337
+ },
338
+ ]),
339
+ );
340
+
341
+ expect(refs.hostNames).toEqual([]);
342
+ expect(refs.podmanHostNames).toEqual(["podman-prod-01"]);
343
+ });
344
+
345
+ test("a Host monitor's resource.host.name filter DOES name a Host", () => {
346
+ // Same key, different monitor type — here it genuinely is a Host.
347
+ const refs: SeriesResourceRefs = refsFor(
348
+ monitorWithSteps(MonitorType.Host, [
349
+ {
350
+ hostMonitor: {
351
+ hostIdentifier: "prod-01",
352
+ metricViewConfig: metricViewConfigWith({
353
+ "resource.host.name": "prod-01",
354
+ }),
355
+ },
356
+ },
357
+ ]),
358
+ );
359
+
360
+ expect(refs.hostNames).toEqual(["prod-01"]);
361
+ });
362
+ });
363
+
364
+ describe("MonitorStepResourceIdentity — monitor types with no resource identity", () => {
365
+ test.each([
366
+ MonitorType.Website,
367
+ MonitorType.API,
368
+ MonitorType.Ping,
369
+ MonitorType.IP,
370
+ MonitorType.Port,
371
+ MonitorType.SSLCertificate,
372
+ MonitorType.Domain,
373
+ MonitorType.DNS,
374
+ MonitorType.SQLQuery,
375
+ MonitorType.SyntheticMonitor,
376
+ MonitorType.CustomJavaScriptCode,
377
+ MonitorType.IncomingRequest,
378
+ MonitorType.IncomingEmail,
379
+ MonitorType.Server,
380
+ MonitorType.Manual,
381
+ MonitorType.NetworkDevice,
382
+ MonitorType.ExternalStatusPage,
383
+ ])("%s names no resource", (monitorType: MonitorType) => {
384
+ const refs: SeriesResourceRefs = refsFor(
385
+ monitorWithSteps(monitorType, [{}]),
386
+ );
387
+
388
+ expect(MonitorStepResourceIdentity.isEmpty(refs)).toBe(true);
389
+ });
390
+
391
+ test("a monitor with no steps at all names no resource", () => {
392
+ const model: Monitor = new Monitor();
393
+ model.monitorType = MonitorType.Host;
394
+
395
+ expect(MonitorStepResourceIdentity.isEmpty(refsFor(model))).toBe(true);
396
+ });
397
+
398
+ test("a monitor with no monitorType names no resource", () => {
399
+ const model: Monitor = new Monitor();
400
+
401
+ expect(MonitorStepResourceIdentity.isEmpty(refsFor(model))).toBe(true);
402
+ });
403
+ });
404
+
405
+ describe("MonitorStepResourceIdentity — multi-query metric steps", () => {
406
+ test("names every service its queries filter on", () => {
407
+ /*
408
+ * A metric step can hold several queries, and the UI lets a user add
409
+ * them. Two queries filtering the same attribute on different
410
+ * services both name a real resource; collapsing them to the last
411
+ * one silently drops a service from Affected Resources, from its
412
+ * Activity tab, and from owner/label inheritance.
413
+ */
414
+ const refs: SeriesResourceRefs = refsFor(
415
+ monitorWithSteps(MonitorType.Metrics, [
416
+ {
417
+ metricMonitor: {
418
+ metricViewConfig: {
419
+ queryConfigs: [
420
+ {
421
+ metricQueryData: {
422
+ filterData: {
423
+ metricName: "a",
424
+ attributes: { "oneuptime.service.name": "checkout-api" },
425
+ },
426
+ },
427
+ },
428
+ {
429
+ metricQueryData: {
430
+ filterData: {
431
+ metricName: "b",
432
+ attributes: { "oneuptime.service.name": "payments-api" },
433
+ },
434
+ },
435
+ },
436
+ ],
437
+ formulaConfigs: [],
438
+ },
439
+ },
440
+ },
441
+ ]),
442
+ );
443
+
444
+ expect(refs.serviceNames.sort()).toEqual(["checkout-api", "payments-api"]);
445
+ });
446
+ });
447
+
448
+ describe("MonitorStepResourceIdentity — malformed step configuration", () => {
449
+ /*
450
+ * Step JSON is persisted free-form and never schema-checked, so the
451
+ * API, a seed, an import or an older build can write shapes the types
452
+ * say are impossible. This module runs inside the probe and telemetry
453
+ * queue workers: a TypeError here would fail the whole job and retry
454
+ * forever, so it must degrade to "names nothing" instead of throwing.
455
+ */
456
+ test.each([
457
+ ["an object", {}],
458
+ ["a number", 123],
459
+ ["a string", "not-an-array"],
460
+ ["null", null],
461
+ ])(
462
+ "does not throw when telemetryServiceIds is %s",
463
+ (_label: string, value: unknown) => {
464
+ const monitor: Monitor = monitorWithSteps(MonitorType.Logs, [
465
+ { logMonitor: { telemetryServiceIds: value } } as unknown as JSONObject,
466
+ ]);
467
+
468
+ expect(() => {
469
+ return refsFor(monitor);
470
+ }).not.toThrow();
471
+
472
+ expect(refsFor(monitor).serviceIds).toEqual([]);
473
+ },
474
+ );
475
+
476
+ test.each([
477
+ ["a number", 12345],
478
+ ["an object", { name: "prod-01" }],
479
+ ["null", null],
480
+ ])(
481
+ "does not throw when a declared identifier is %s",
482
+ (_label: string, value: unknown) => {
483
+ const monitor: Monitor = monitorWithSteps(MonitorType.Host, [
484
+ { hostMonitor: { hostIdentifier: value } } as unknown as JSONObject,
485
+ ]);
486
+
487
+ expect(() => {
488
+ return refsFor(monitor);
489
+ }).not.toThrow();
490
+
491
+ expect(refsFor(monitor).hostNames).toEqual([]);
492
+ },
493
+ );
494
+
495
+ test("drops a non-scalar service id rather than stringifying it", () => {
496
+ /*
497
+ * `String({})` is "[object Object]" — a lookup key that can never
498
+ * match, but that would still cost a query and pollute the refs.
499
+ */
500
+ const refs: SeriesResourceRefs = refsFor(
501
+ monitorWithSteps(MonitorType.Logs, [
502
+ {
503
+ logMonitor: { telemetryServiceIds: [{ nested: "object" }] },
504
+ } as unknown as JSONObject,
505
+ ]),
506
+ );
507
+
508
+ expect(refs.serviceIds).toEqual([]);
509
+ });
510
+
511
+ test("does not throw when a metric view config is malformed", () => {
512
+ const monitor: Monitor = monitorWithSteps(MonitorType.Metrics, [
513
+ {
514
+ metricMonitor: { metricViewConfig: { queryConfigs: "nope" } },
515
+ } as unknown as JSONObject,
516
+ ]);
517
+
518
+ expect(() => {
519
+ return refsFor(monitor);
520
+ }).not.toThrow();
521
+ });
522
+ });
523
+
524
+ describe("MonitorStepResourceIdentity — persisted monitors", () => {
525
+ /*
526
+ * Production never sees a hand-built MonitorSteps: it reads one that
527
+ * has been through toJSON on the way into Postgres and fromJSON on the
528
+ * way out. If an ObjectID does not survive that round trip as
529
+ * something String() can render, the ids become "[object Object]" and
530
+ * every lookup silently misses. These pin the shape that actually
531
+ * reaches the extractor.
532
+ */
533
+ function roundTrip(monitorType: MonitorType, stepData: JSONObject): Monitor {
534
+ const built: Monitor = monitorWithSteps(monitorType, [stepData]);
535
+
536
+ const rehydrated: MonitorSteps = MonitorSteps.fromJSON(
537
+ JSON.parse(JSON.stringify(built.monitorSteps!.toJSON())) as JSONObject,
538
+ ) as MonitorSteps;
539
+
540
+ const model: Monitor = new Monitor();
541
+ model.monitorType = monitorType;
542
+ model.projectId = new ObjectID("11111111-1111-4111-8111-111111111111");
543
+ model.monitorSteps = rehydrated;
544
+ return model;
545
+ }
546
+
547
+ test("telemetryServiceIds survive a persist / rehydrate round trip", () => {
548
+ const refs: SeriesResourceRefs = refsFor(
549
+ roundTrip(MonitorType.Logs, {
550
+ logMonitor: {
551
+ attributes: {},
552
+ body: "",
553
+ severityTexts: [],
554
+ lastXSecondsOfLogs: 60,
555
+ telemetryServiceIds: [new ObjectID(SERVICE_ID_A)],
556
+ },
557
+ }),
558
+ );
559
+
560
+ expect(refs.serviceIds).toEqual([SERVICE_ID_A]);
561
+ });
562
+
563
+ test("a metric filter survives a persist / rehydrate round trip", () => {
564
+ const refs: SeriesResourceRefs = refsFor(
565
+ roundTrip(MonitorType.Metrics, {
566
+ metricMonitor: {
567
+ rollingTime: "Past 1 Minute",
568
+ metricViewConfig: metricViewConfigWith({
569
+ "oneuptime.service.name": "app-plan-starship-online-production",
570
+ }),
571
+ },
572
+ }),
573
+ );
574
+
575
+ expect(refs.serviceNames).toEqual(["app-plan-starship-online-production"]);
576
+ });
577
+
578
+ test("a declared host identifier survives a persist / rehydrate round trip", () => {
579
+ const refs: SeriesResourceRefs = refsFor(
580
+ roundTrip(MonitorType.Host, {
581
+ hostMonitor: {
582
+ hostIdentifier: "prod-01",
583
+ rollingTime: "Past 1 Minute",
584
+ metricViewConfig: { queryConfigs: [], formulaConfigs: [] },
585
+ },
586
+ }),
587
+ );
588
+
589
+ expect(refs.hostNames).toEqual(["prod-01"]);
590
+ });
591
+
592
+ test("no id ever renders as [object Object]", () => {
593
+ /*
594
+ * The failure mode this whole describe exists to catch: a
595
+ * half-rehydrated ObjectID stringifies to "[object Object]" and the
596
+ * lookup quietly matches nothing.
597
+ */
598
+ const refs: SeriesResourceRefs = refsFor(
599
+ roundTrip(MonitorType.Metrics, {
600
+ metricMonitor: {
601
+ rollingTime: "Past 1 Minute",
602
+ telemetryServiceIds: [new ObjectID(SERVICE_ID_A)],
603
+ metricViewConfig: { queryConfigs: [], formulaConfigs: [] },
604
+ },
605
+ }),
606
+ );
607
+
608
+ for (const values of Object.values(refs)) {
609
+ for (const value of values) {
610
+ expect(value).not.toContain("[object");
611
+ }
612
+ }
613
+
614
+ expect(refs.serviceIds).toEqual([SERVICE_ID_A]);
615
+ });
616
+ });
617
+
618
+ describe("MonitorStepResourceIdentity — multiple steps", () => {
619
+ test("names the union across steps", () => {
620
+ /*
621
+ * The creation path does not know which step fired, so a monitor
622
+ * watching three hosts names all three. Attributing nothing is the
623
+ * bug this module exists to fix.
624
+ */
625
+ const refs: SeriesResourceRefs = refsFor(
626
+ monitorWithSteps(MonitorType.Host, [
627
+ { hostMonitor: { hostIdentifier: "prod-01" } },
628
+ { hostMonitor: { hostIdentifier: "prod-02" } },
629
+ ]),
630
+ );
631
+
632
+ expect(refs.hostNames.sort()).toEqual(["prod-01", "prod-02"]);
633
+ });
634
+
635
+ test("dedupes a resource named by two steps", () => {
636
+ const refs: SeriesResourceRefs = refsFor(
637
+ monitorWithSteps(MonitorType.Host, [
638
+ { hostMonitor: { hostIdentifier: "prod-01" } },
639
+ { hostMonitor: { hostIdentifier: "prod-01" } },
640
+ ]),
641
+ );
642
+
643
+ expect(refs.hostNames).toEqual(["prod-01"]);
644
+ });
645
+
646
+ test("dedupes a service named by both the filter and another step", () => {
647
+ const refs: SeriesResourceRefs = refsFor(
648
+ monitorWithSteps(MonitorType.Metrics, [
649
+ {
650
+ metricMonitor: {
651
+ metricViewConfig: metricViewConfigWith({
652
+ "service.name": "checkout-api",
653
+ }),
654
+ },
655
+ },
656
+ {
657
+ metricMonitor: {
658
+ metricViewConfig: metricViewConfigWith({
659
+ "oneuptime.service.name": "checkout-api",
660
+ }),
661
+ },
662
+ },
663
+ ]),
664
+ );
665
+
666
+ expect(refs.serviceNames).toEqual(["checkout-api"]);
667
+ });
668
+
669
+ test("collects the declared identifier and the filter identity together", () => {
670
+ /*
671
+ * A Kubernetes monitor names its cluster in the step config and can
672
+ * additionally scope itself to a service by filter. Both are real.
673
+ */
674
+ const refs: SeriesResourceRefs = refsFor(
675
+ monitorWithSteps(MonitorType.Kubernetes, [
676
+ {
677
+ kubernetesMonitor: {
678
+ clusterIdentifier: "prod-cluster",
679
+ metricViewConfig: metricViewConfigWith({
680
+ "service.name": "checkout-api",
681
+ }),
682
+ },
683
+ },
684
+ ]),
685
+ );
686
+
687
+ expect(refs.kubernetesClusterNames).toEqual(["prod-cluster"]);
688
+ expect(refs.serviceNames).toEqual(["checkout-api"]);
689
+ });
690
+ });
@@ -5,7 +5,7 @@ import AlertService from "../../../../Server/Services/AlertService";
5
5
  import IncidentService from "../../../../Server/Services/IncidentService";
6
6
  import NetworkDeviceOwnerUserService from "../../../../Server/Services/NetworkDeviceOwnerUserService";
7
7
  import MonitorAlert from "../../../../Server/Utils/Monitor/MonitorAlert";
8
- import MonitorClusterContextUtil from "../../../../Server/Utils/Monitor/MonitorClusterContext";
8
+ import MonitorResourceContextUtil from "../../../../Server/Utils/Monitor/MonitorResourceContext";
9
9
  import MonitorIncident from "../../../../Server/Utils/Monitor/MonitorIncident";
10
10
  import ProjectScopedReferenceValidator from "../../../../Server/Utils/Database/ProjectScopedReferenceValidator";
11
11
  import Dictionary from "../../../../Types/Dictionary";
@@ -132,8 +132,13 @@ describe("The monitor summary is stored on the incident / alert it created", ()
132
132
  .mockResolvedValue(true);
133
133
 
134
134
  jest
135
- .spyOn(MonitorClusterContextUtil, "resolveClusterContextForMonitor")
135
+ .spyOn(MonitorResourceContextUtil, "resolveResourceContextForMonitor")
136
136
  .mockResolvedValue({
137
+ hostIds: [],
138
+ dockerHostIds: [],
139
+ podmanHostIds: [],
140
+ kubernetesClusterIds: [],
141
+ serviceIds: [],
137
142
  proxmoxClusterIds: [],
138
143
  cephClusterIds: [],
139
144
  dockerSwarmClusterIds: [],