@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
@@ -644,6 +644,14 @@ export class Service extends DatabaseService<Model> {
644
644
  deviceType: true,
645
645
  isVerified: true,
646
646
  userId: true,
647
+ /*
648
+ * Whether this handset asked to be rung through silent mode. Unselected
649
+ * it reads as undefined, which Boolean()s to false further down - the
650
+ * page still goes out, just quietly, which is the wrong outcome for the
651
+ * one channel a sleeping responder relies on. It is selected here so
652
+ * that cannot happen.
653
+ */
654
+ isCriticalAlertEnabled: true,
647
655
  },
648
656
  },
649
657
  props: {
@@ -2419,6 +2427,16 @@ export class Service extends DatabaseService<Model> {
2419
2427
  notificationRuleItem.userPush?.deviceToken &&
2420
2428
  notificationRuleItem.userPush?.isVerified
2421
2429
  ) {
2430
+ /*
2431
+ * This is the on-call paging path - the notification that exists to wake
2432
+ * somebody at 3am - so it is the only push in the product allowed to
2433
+ * override the ringer switch, and then only for a device whose owner
2434
+ * turned the option on. Owner subscriptions and note-posted notifications
2435
+ * go out through UserNotificationSettingService and never set this.
2436
+ */
2437
+ const isCriticalAlert: boolean = Boolean(
2438
+ notificationRuleItem.userPush.isCriticalAlertEnabled,
2439
+ );
2422
2440
  // send push notification for alert
2423
2441
  if (
2424
2442
  options.userNotificationEventType ===
@@ -2459,6 +2477,8 @@ export class Service extends DatabaseService<Model> {
2459
2477
  projectId: alert.projectId!.toString(),
2460
2478
  });
2461
2479
 
2480
+ pushMessage.isCriticalAlert = isCriticalAlert;
2481
+
2462
2482
  // send push notification.
2463
2483
  PushNotificationService.sendPushNotification(
2464
2484
  {
@@ -2540,6 +2560,8 @@ export class Service extends DatabaseService<Model> {
2540
2560
  projectId: incident.projectId!.toString(),
2541
2561
  });
2542
2562
 
2563
+ pushMessage.isCriticalAlert = isCriticalAlert;
2564
+
2543
2565
  // send push notification.
2544
2566
  PushNotificationService.sendPushNotification(
2545
2567
  {
@@ -2620,6 +2642,8 @@ export class Service extends DatabaseService<Model> {
2620
2642
  projectId: alertEpisode.projectId!.toString(),
2621
2643
  });
2622
2644
 
2645
+ pushMessage.isCriticalAlert = isCriticalAlert;
2646
+
2623
2647
  PushNotificationService.sendPushNotification(
2624
2648
  {
2625
2649
  devices: [
@@ -2699,6 +2723,8 @@ export class Service extends DatabaseService<Model> {
2699
2723
  projectId: incidentEpisode.projectId!.toString(),
2700
2724
  });
2701
2725
 
2726
+ pushMessage.isCriticalAlert = isCriticalAlert;
2727
+
2702
2728
  PushNotificationService.sendPushNotification(
2703
2729
  {
2704
2730
  devices: [
@@ -12,6 +12,7 @@ import PositiveNumber from "../../Types/PositiveNumber";
12
12
  import PushDeviceType from "../../Types/PushNotification/PushDeviceType";
13
13
  import UserPush from "../../Models/DatabaseModels/UserPush";
14
14
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
15
+ import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
15
16
 
16
17
  export class Service extends DatabaseService<UserPush> {
17
18
  public constructor() {
@@ -120,6 +121,94 @@ export class Service extends DatabaseService<UserPush> {
120
121
  },
121
122
  });
122
123
  }
124
+
125
+ /**
126
+ * Turn on-call critical alerts on or off for a handset.
127
+ *
128
+ * Keyed on the device TOKEN rather than a row id, because one phone owns one
129
+ * row per project it is registered against, and "ring me through silent
130
+ * mode" is a property of the phone. Toggling it per row would leave a
131
+ * responder loud for one project and silent for the next - a distinction
132
+ * nothing in the app offers to make and nobody would think to check.
133
+ * Deletion already works this way for the same reason (see the unregister
134
+ * route).
135
+ *
136
+ * Scoped to `userId` so a token cannot be used to reconfigure somebody
137
+ * else's device, and to the two mobile platforms because no browser can
138
+ * override a device's ringer: storing the preference on a web row would
139
+ * read back as though it did something.
140
+ *
141
+ * Returns how many rows were updated, so the caller can tell a real toggle
142
+ * apart from one that matched no device at all.
143
+ */
144
+ @CaptureSpan()
145
+ public async setCriticalAlertEnabledForDeviceToken(data: {
146
+ userId: ObjectID;
147
+ deviceToken: string;
148
+ isEnabled: boolean;
149
+ }): Promise<number> {
150
+ const devices: Array<UserPush> = await this.findBy({
151
+ query: {
152
+ userId: data.userId,
153
+ deviceToken: data.deviceToken,
154
+ },
155
+ select: {
156
+ _id: true,
157
+ deviceType: true,
158
+ },
159
+ limit: LIMIT_PER_PROJECT,
160
+ skip: 0,
161
+ props: {
162
+ isRoot: true,
163
+ },
164
+ });
165
+
166
+ if (devices.length === 0) {
167
+ throw new BadDataException(
168
+ "No registered device was found for this device token.",
169
+ );
170
+ }
171
+
172
+ const mobileDeviceIds: Array<string> = devices
173
+ .filter((device: UserPush) => {
174
+ return (
175
+ device.deviceType === PushDeviceType.iOS ||
176
+ device.deviceType === PushDeviceType.Android
177
+ );
178
+ })
179
+ .map((device: UserPush) => {
180
+ return device._id!.toString();
181
+ });
182
+
183
+ if (mobileDeviceIds.length === 0) {
184
+ throw new BadDataException(
185
+ "Critical alerts are only available on iOS and Android devices.",
186
+ );
187
+ }
188
+
189
+ let updatedCount: number = 0;
190
+
191
+ /*
192
+ * One update per row rather than an `_id: In([...])` query: the query
193
+ * builder used here takes a single value per column, and the count of
194
+ * projects a responder belongs to is small.
195
+ */
196
+ for (const deviceId of mobileDeviceIds) {
197
+ updatedCount += await this.updateOneBy({
198
+ query: {
199
+ _id: deviceId,
200
+ },
201
+ data: {
202
+ isCriticalAlertEnabled: data.isEnabled,
203
+ },
204
+ props: {
205
+ isRoot: true,
206
+ },
207
+ });
208
+ }
209
+
210
+ return updatedCount;
211
+ }
123
212
  }
124
213
 
125
214
  export default new Service();
@@ -15,7 +15,8 @@ import LIMIT_MAX from "../../Types/Database/LimitMax";
15
15
  import TwilioConfig from "../../Types/CallAndSMS/TwilioConfig";
16
16
  import BadDataException from "../../Types/Exception/BadDataException";
17
17
  import ObjectID from "../../Types/ObjectID";
18
- import Text from "../../Types/Text";
18
+ import TooManyRequestsException from "../../Types/Exception/TooManyRequestsException";
19
+ import ChannelVerification from "../Utils/ChannelVerification";
19
20
  import Project from "../../Models/DatabaseModels/Project";
20
21
  import Model from "../../Models/DatabaseModels/UserSMS";
21
22
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
@@ -143,7 +144,8 @@ export class Service extends DatabaseService<Model> {
143
144
  createdItem: Model,
144
145
  ): Promise<Model> {
145
146
  if (!createdItem.isVerified) {
146
- this.sendVerificationCode(createdItem);
147
+ // issue and send the first verification code
148
+ await this.issueAndSendVerificationCode(createdItem);
147
149
  }
148
150
 
149
151
  return createdItem;
@@ -158,9 +160,10 @@ export class Service extends DatabaseService<Model> {
158
160
  },
159
161
  select: {
160
162
  phone: true,
161
- verificationCode: true,
162
163
  isVerified: true,
163
164
  projectId: true,
165
+ userId: true,
166
+ verificationCodeSentAt: true,
164
167
  },
165
168
  });
166
169
 
@@ -215,23 +218,54 @@ export class Service extends DatabaseService<Model> {
215
218
  );
216
219
  }
217
220
 
218
- // generate new verification code
219
- item.verificationCode = Text.generateRandomNumber(6);
221
+ /*
222
+ * Resend cooldown.
223
+ *
224
+ * Without it, spending the attempt budget on a code and asking for
225
+ * another one is free, which turns the attempt limit into a speed bump
226
+ * rather than a wall — and the resend control doubles as a way to send
227
+ * somebody unsolicited messages as fast as the network allows, at the
228
+ * project's expense.
229
+ */
230
+ const retryAfterSeconds: number =
231
+ ChannelVerification.getResendRetryAfterSeconds({
232
+ lastSentAt: item.verificationCodeSentAt,
233
+ });
220
234
 
221
- await this.updateOneById({
222
- id: item.id!,
223
- props: {
224
- isRoot: true,
225
- },
226
- data: {
227
- verificationCode: item.verificationCode,
228
- },
235
+ if (retryAfterSeconds > 0) {
236
+ throw new TooManyRequestsException(
237
+ `Please wait ${retryAfterSeconds} seconds before requesting another verification code.`,
238
+ );
239
+ }
240
+
241
+ await this.issueAndSendVerificationCode(item);
242
+ }
243
+
244
+ /*
245
+ * Mint a fresh code for this row, store only its digest, and send the
246
+ * plaintext to the channel.
247
+ *
248
+ * The plaintext exists in memory for exactly as long as it takes to hand it
249
+ * to the notification service and is never written anywhere. Everything
250
+ * about why — expiry, the attempt counter, rotation, the resend cooldown —
251
+ * is in Common/Server/Utils/ChannelVerification.ts.
252
+ *
253
+ * This does NOT check whether a send is allowed. Callers decide that:
254
+ * onCreateSuccess because a brand new row has never been sent to, and
255
+ * resendVerificationCode after the cooldown and the channel's own
256
+ * preconditions have passed.
257
+ */
258
+ @CaptureSpan()
259
+ public async issueAndSendVerificationCode(item: Model): Promise<void> {
260
+ const plainCode: string = await ChannelVerification.issueCodeOnItem({
261
+ service: this,
262
+ itemId: item.id!,
229
263
  });
230
264
 
231
- this.sendVerificationCode(item);
265
+ this.sendVerificationCode(item, plainCode);
232
266
  }
233
267
 
234
- public sendVerificationCode(item: Model): void {
268
+ public sendVerificationCode(item: Model, code: string): void {
235
269
  (async () => {
236
270
  const projectTwilioConfig: TwilioConfig | undefined =
237
271
  await ProjectCallSMSConfigService.getProjectDefaultTwilioConfig(
@@ -242,8 +276,7 @@ export class Service extends DatabaseService<Model> {
242
276
  {
243
277
  to: item.phone!,
244
278
  message:
245
- "This message is from OneUptime. Your verification code is " +
246
- item.verificationCode,
279
+ "This message is from OneUptime. Your verification code is " + code,
247
280
  },
248
281
  {
249
282
  projectId: item.projectId,
@@ -13,7 +13,8 @@ import WhatsAppService from "./WhatsAppService";
13
13
  import LIMIT_MAX from "../../Types/Database/LimitMax";
14
14
  import BadDataException from "../../Types/Exception/BadDataException";
15
15
  import ObjectID from "../../Types/ObjectID";
16
- import Text from "../../Types/Text";
16
+ import TooManyRequestsException from "../../Types/Exception/TooManyRequestsException";
17
+ import ChannelVerification from "../Utils/ChannelVerification";
17
18
  import Project from "../../Models/DatabaseModels/Project";
18
19
  import Model from "../../Models/DatabaseModels/UserWhatsApp";
19
20
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
@@ -139,7 +140,7 @@ export class Service extends DatabaseService<Model> {
139
140
  createdItem: Model,
140
141
  ): Promise<Model> {
141
142
  if (!createdItem.isVerified) {
142
- this.sendVerificationCode(createdItem).catch((error: Error) => {
143
+ this.issueAndSendVerificationCode(createdItem).catch((error: Error) => {
143
144
  logger.error(error, {
144
145
  projectId: createdItem.projectId?.toString(),
145
146
  userId: createdItem.userId?.toString(),
@@ -159,10 +160,10 @@ export class Service extends DatabaseService<Model> {
159
160
  },
160
161
  select: {
161
162
  phone: true,
162
- verificationCode: true,
163
163
  isVerified: true,
164
164
  projectId: true,
165
165
  userId: true,
166
+ verificationCodeSentAt: true,
166
167
  },
167
168
  });
168
169
 
@@ -176,22 +177,54 @@ export class Service extends DatabaseService<Model> {
176
177
  throw new BadDataException("WhatsApp number already verified");
177
178
  }
178
179
 
179
- item.verificationCode = Text.generateRandomNumber(6);
180
+ /*
181
+ * Resend cooldown.
182
+ *
183
+ * Without it, spending the attempt budget on a code and asking for
184
+ * another one is free, which turns the attempt limit into a speed bump
185
+ * rather than a wall — and the resend control doubles as a way to send
186
+ * somebody unsolicited messages as fast as the network allows, at the
187
+ * project's expense.
188
+ */
189
+ const retryAfterSeconds: number =
190
+ ChannelVerification.getResendRetryAfterSeconds({
191
+ lastSentAt: item.verificationCodeSentAt,
192
+ });
180
193
 
181
- await this.updateOneById({
182
- id: item.id!,
183
- props: {
184
- isRoot: true,
185
- },
186
- data: {
187
- verificationCode: item.verificationCode,
188
- },
194
+ if (retryAfterSeconds > 0) {
195
+ throw new TooManyRequestsException(
196
+ `Please wait ${retryAfterSeconds} seconds before requesting another verification code.`,
197
+ );
198
+ }
199
+
200
+ await this.issueAndSendVerificationCode(item);
201
+ }
202
+
203
+ /*
204
+ * Mint a fresh code for this row, store only its digest, and send the
205
+ * plaintext to the channel.
206
+ *
207
+ * The plaintext exists in memory for exactly as long as it takes to hand it
208
+ * to the notification service and is never written anywhere. Everything
209
+ * about why — expiry, the attempt counter, rotation, the resend cooldown —
210
+ * is in Common/Server/Utils/ChannelVerification.ts.
211
+ *
212
+ * This does NOT check whether a send is allowed. Callers decide that:
213
+ * onCreateSuccess because a brand new row has never been sent to, and
214
+ * resendVerificationCode after the cooldown and the channel's own
215
+ * preconditions have passed.
216
+ */
217
+ @CaptureSpan()
218
+ public async issueAndSendVerificationCode(item: Model): Promise<void> {
219
+ const plainCode: string = await ChannelVerification.issueCodeOnItem({
220
+ service: this,
221
+ itemId: item.id!,
189
222
  });
190
223
 
191
- await this.sendVerificationCode(item);
224
+ await this.sendVerificationCode(item, plainCode);
192
225
  }
193
226
 
194
- public async sendVerificationCode(item: Model): Promise<void> {
227
+ public async sendVerificationCode(item: Model, code: string): Promise<void> {
195
228
  if (!item.projectId || !item.userId || !item.phone) {
196
229
  logger.warn("Cannot send WhatsApp verification code. Missing data.", {
197
230
  projectId: item.projectId?.toString(),
@@ -205,7 +238,7 @@ export class Service extends DatabaseService<Model> {
205
238
  const templateKey: WhatsAppTemplateId =
206
239
  WhatsAppTemplateIds.VerificationCode;
207
240
  const templateVariables: Record<string, string> = {
208
- "1": item.verificationCode || "",
241
+ "1": code,
209
242
  };
210
243
 
211
244
  const whatsAppMessage: WhatsAppMessage = {
@@ -51,6 +51,36 @@ export default class QueryHelper {
51
51
  );
52
52
  }
53
53
 
54
+ /*
55
+ * Case-insensitive `IN (...)` — the multi-value twin of
56
+ * findWithSameText. Used where a user-typed identifier has to match an
57
+ * ingest-stamped name that may differ only by case (monitor step
58
+ * configs vs. the resource rows discovered from telemetry), and where
59
+ * issuing one findOneBy per identifier would cost a round-trip each.
60
+ *
61
+ * An empty list would compile to `IN ()`, which is a syntax error, so
62
+ * callers must not pass one; they have nothing to look up anyway.
63
+ */
64
+ @CaptureSpan()
65
+ public static findWithSameTextAnyOf(
66
+ texts: Array<string>,
67
+ ): FindWhereProperty<any> {
68
+ const rid: string = Text.generateRandomText(10);
69
+
70
+ const normalizedTexts: Array<string> = texts.map((text: string): string => {
71
+ return text.toLowerCase().trim();
72
+ });
73
+
74
+ return Raw(
75
+ (alias: string) => {
76
+ return `(LOWER(${alias}) IN (:...${rid}))`;
77
+ },
78
+ {
79
+ [rid]: normalizedTexts,
80
+ },
81
+ );
82
+ }
83
+
54
84
  @CaptureSpan()
55
85
  public static isNull(): any {
56
86
  return Raw((alias: string) => {
@@ -25,6 +25,46 @@ export const DEFAULT_MAX_BYTES_BEFORE_EXTERNAL_GROUP_BY_IN_BYTES: number = 16106
25
25
  // 1.5 GiB.
26
26
  export const DEFAULT_MAX_BYTES_BEFORE_EXTERNAL_SORT_IN_BYTES: number = 1610612736;
27
27
 
28
+ /*
29
+ * Scan-side memory bound for wide-window aggregations.
30
+ *
31
+ * A GROUP BY over a log window has to visit every matching row, so unlike a
32
+ * paginated list it cannot be made to read less. What it CAN be stopped from
33
+ * doing is holding a huge amount of that data in flight at once: peak memory
34
+ * is roughly (threads x block rows x bytes per row), and a row carrying the
35
+ * fat `attributes` Map(String, String) is expensive. Reading the default
36
+ * 65536 rows per block per thread is what pushes a filtered facet or a
37
+ * projection-fallback histogram past max_memory_usage and into Code 241.
38
+ *
39
+ * These are execution-strategy settings only — ClickHouse returns the same
40
+ * rows either way (asserted in QuerySettingsHelper.test.ts and verified
41
+ * against a real server).
42
+ *
43
+ * Measured on ClickHouse 26.7, 3M rows shaped like LogItemV3, one facet
44
+ * query filtered on an attribute:
45
+ *
46
+ * default 695 MiB peak
47
+ * max_block_size alone 88 MiB peak (and faster)
48
+ * + preferred_block_size_bytes, threads 40 MiB peak
49
+ *
50
+ * NOTE: this bounds SCAN memory, not aggregation state. A facet on a
51
+ * genuinely high-cardinality attribute builds a large hash table regardless;
52
+ * that case is covered by max_bytes_before_external_group_by spilling to
53
+ * disk, which is already applied to every read here.
54
+ */
55
+ export const AGGREGATION_SCAN_MAX_BLOCK_SIZE: number = 8192;
56
+
57
+ // 1 MiB — caps a block by bytes when rows are unusually wide.
58
+ export const AGGREGATION_SCAN_PREFERRED_BLOCK_SIZE_IN_BYTES: number = 1048576;
59
+
60
+ /*
61
+ * The Logs sidebar fans out one aggregation per facet key concurrently, so
62
+ * per-query thread caps also bound how much of the server a single page load
63
+ * can claim. Latency is barely affected — these queries are already bounded
64
+ * by max_execution_time with 'break'.
65
+ */
66
+ export const AGGREGATION_SCAN_MAX_THREADS: number = 4;
67
+
28
68
  export interface QuerySettingsOptions {
29
69
  /**
30
70
  * Wall-clock cap in seconds (max_execution_time). Omitted from the
@@ -40,6 +80,13 @@ export interface QuerySettingsOptions {
40
80
  maxMemoryUsageInBytes?: number | undefined;
41
81
  maxBytesBeforeExternalGroupByInBytes?: number | undefined;
42
82
  maxBytesBeforeExternalSortInBytes?: number | undefined;
83
+ /**
84
+ * Bounds how much data a scan holds in flight, for aggregations that must
85
+ * visit every row in a wide window. Emits max_block_size,
86
+ * preferred_block_size_bytes and max_threads. Execution strategy only —
87
+ * the result set is unchanged. See AGGREGATION_SCAN_MAX_BLOCK_SIZE.
88
+ */
89
+ boundScanMemory?: boolean | undefined;
43
90
  /**
44
91
  * Site-specific passthrough settings (e.g. optimize_use_projections,
45
92
  * optimize_aggregation_in_order, max_threads). Keys and values are
@@ -77,6 +124,18 @@ export function getQuerySettings(options?: QuerySettingsOptions): string {
77
124
  }`,
78
125
  );
79
126
 
127
+ /*
128
+ * Emitted before additionalSettings so a call site can still override any
129
+ * one of these explicitly if it has a reason to.
130
+ */
131
+ if (options?.boundScanMemory) {
132
+ parts.push(`max_block_size = ${AGGREGATION_SCAN_MAX_BLOCK_SIZE}`);
133
+ parts.push(
134
+ `preferred_block_size_bytes = ${AGGREGATION_SCAN_PREFERRED_BLOCK_SIZE_IN_BYTES}`,
135
+ );
136
+ parts.push(`max_threads = ${AGGREGATION_SCAN_MAX_THREADS}`);
137
+ }
138
+
80
139
  if (options?.additionalSettings) {
81
140
  for (const [key, value] of Object.entries(options.additionalSettings)) {
82
141
  parts.push(