@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,338 @@
1
+ import {
2
+ afterEach,
3
+ beforeEach,
4
+ describe,
5
+ expect,
6
+ jest,
7
+ test,
8
+ } from "@jest/globals";
9
+ import "@testing-library/jest-dom";
10
+ import {
11
+ act,
12
+ cleanup,
13
+ fireEvent,
14
+ render,
15
+ screen,
16
+ } from "@testing-library/react";
17
+ import * as React from "react";
18
+ import getJestMockFunction, { MockFunction } from "../../MockType";
19
+
20
+ /*
21
+ * The flagship interaction of the command palette — press Cmd/Ctrl+K anywhere
22
+ * on the dashboard and the palette appears — lives entirely in the
23
+ * DashboardCommandPalette host: a document-level keydown listener plus a
24
+ * GlobalEvents subscription. The App suite runs in plain node and can only
25
+ * pin source patterns, so this suite actually mounts the host (real
26
+ * CommandPalette underneath, portal and all) and fires the real events.
27
+ *
28
+ * Escape/close-key semantics inside the open palette are deliberately NOT
29
+ * pinned here — they belong to the Common CommandPalette's own contract. This
30
+ * suite owns only the host's chord, its politeness rules, the global toggle
31
+ * event, and listener cleanup.
32
+ */
33
+
34
+ const navigateMock: MockFunction = getJestMockFunction();
35
+ const getListMock: MockFunction = getJestMockFunction();
36
+ const getCurrentProjectIdMock: MockFunction = getJestMockFunction();
37
+ const getAllPermissionsMock: MockFunction = getJestMockFunction();
38
+ const isMasterAdminMock: MockFunction = getJestMockFunction();
39
+
40
+ /*
41
+ * The arrow wrappers are load bearing: jest.mock is hoisted above the
42
+ * compiled requires, so the consts above are still in their temporal dead
43
+ * zone when the factory body runs. Dereferencing them lazily, at call time,
44
+ * is what works (same pattern as InvestigationPanel.test.tsx).
45
+ */
46
+ jest.mock("react-i18next", () => {
47
+ return {
48
+ useTranslation: () => {
49
+ return {
50
+ t: (key: string, defaultValue?: string): string => {
51
+ return defaultValue ?? key;
52
+ },
53
+ };
54
+ },
55
+ };
56
+ });
57
+
58
+ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
59
+ return {
60
+ __esModule: true,
61
+ default: {
62
+ getList: (...args: Array<unknown>) => {
63
+ return getListMock(...args);
64
+ },
65
+ },
66
+ };
67
+ });
68
+
69
+ jest.mock("../../../UI/Utils/Navigation", () => {
70
+ return {
71
+ __esModule: true,
72
+ default: {
73
+ navigate: (...args: Array<unknown>) => {
74
+ return navigateMock(...args);
75
+ },
76
+ },
77
+ };
78
+ });
79
+
80
+ jest.mock("../../../UI/Utils/Permission", () => {
81
+ return {
82
+ __esModule: true,
83
+ default: {
84
+ getAllPermissions: (...args: Array<unknown>) => {
85
+ return getAllPermissionsMock(...args);
86
+ },
87
+ },
88
+ };
89
+ });
90
+
91
+ jest.mock("../../../UI/Utils/User", () => {
92
+ return {
93
+ __esModule: true,
94
+ default: {
95
+ isMasterAdmin: (...args: Array<unknown>) => {
96
+ return isMasterAdminMock(...args);
97
+ },
98
+ },
99
+ };
100
+ });
101
+
102
+ jest.mock("../../../UI/Utils/Project", () => {
103
+ return {
104
+ __esModule: true,
105
+ default: {
106
+ getCurrentProjectId: (...args: Array<unknown>) => {
107
+ return getCurrentProjectIdMock(...args);
108
+ },
109
+ },
110
+ };
111
+ });
112
+
113
+ /*
114
+ * The real catalog hook walks the full RouteMap through useTranslation; the
115
+ * host only needs SOME catalog, so a single-page one keeps the suite about
116
+ * the host's event wiring rather than the NavBar's contents.
117
+ */
118
+ jest.mock(
119
+ "../../../../App/FeatureSet/Dashboard/src/Utils/NavigationItems",
120
+ () => {
121
+ const useDashboardNavigationItemsStub: () => unknown = (): unknown => {
122
+ /*
123
+ * Route is loaded lazily for the same hoisting reason as the mock
124
+ * functions above; requireActual keeps it the real class.
125
+ */
126
+ const RouteClass: typeof import("../../../Types/API/Route").default = (
127
+ jest.requireActual("../../../Types/API/Route") as {
128
+ default: typeof import("../../../Types/API/Route").default;
129
+ }
130
+ ).default;
131
+ return {
132
+ navItems: [
133
+ {
134
+ id: "home-nav-bar-item",
135
+ title: "Home",
136
+ icon: "Home",
137
+ route: new RouteClass("/dashboard/abc123/home"),
138
+ },
139
+ ],
140
+ moreMenuItems: [],
141
+ rightElement: {
142
+ id: "user-profile-nav-bar-item",
143
+ title: "User Profile",
144
+ description: "Your account",
145
+ icon: "User",
146
+ route: new RouteClass("/dashboard/user-profile/picture"),
147
+ },
148
+ };
149
+ };
150
+
151
+ // The App source consumes the hook as the module's default export.
152
+ return {
153
+ __esModule: true,
154
+ default: useDashboardNavigationItemsStub,
155
+ useDashboardNavigationItems: useDashboardNavigationItemsStub,
156
+ };
157
+ },
158
+ );
159
+
160
+ import DashboardCommandPalette from "../../../../App/FeatureSet/Dashboard/src/Components/CommandPalette/DashboardCommandPalette";
161
+ import EventName from "../../../../App/FeatureSet/Dashboard/src/Utils/EventName";
162
+ import GlobalEvents from "../../../UI/Utils/GlobalEvents";
163
+
164
+ function palette(): HTMLElement | null {
165
+ return screen.queryByTestId("command-palette");
166
+ }
167
+
168
+ /*
169
+ * The chord is dispatched on document.body — where real key events land when
170
+ * no input is focused — and bubbles up to the host's document-level listener.
171
+ */
172
+ function pressChord(init: KeyboardEventInit): void {
173
+ fireEvent.keyDown(document.body, init);
174
+ }
175
+
176
+ beforeEach(() => {
177
+ /*
178
+ * The open panel schedules an enter-transition frame (rAF + fallback
179
+ * timer); fake timers keep those under act()'s control.
180
+ */
181
+ jest.useFakeTimers();
182
+ getCurrentProjectIdMock.mockReturnValue(null);
183
+ getAllPermissionsMock.mockReturnValue([]);
184
+ isMasterAdminMock.mockReturnValue(false);
185
+ getListMock.mockResolvedValue({ data: [], count: 0 } as never);
186
+ });
187
+
188
+ afterEach(() => {
189
+ cleanup();
190
+ jest.clearAllTimers();
191
+ jest.useRealTimers();
192
+ navigateMock.mockReset();
193
+ getListMock.mockReset();
194
+ getCurrentProjectIdMock.mockReset();
195
+ getAllPermissionsMock.mockReset();
196
+ isMasterAdminMock.mockReset();
197
+ });
198
+
199
+ describe("DashboardCommandPalette Cmd/Ctrl+K chord", () => {
200
+ test("Cmd+K on the document opens the palette", () => {
201
+ render(<DashboardCommandPalette />);
202
+ expect(palette()).toBeNull();
203
+
204
+ pressChord({ key: "k", metaKey: true });
205
+
206
+ expect(palette()).toBeInTheDocument();
207
+ });
208
+
209
+ test("the same chord closes an open palette", () => {
210
+ render(<DashboardCommandPalette />);
211
+
212
+ pressChord({ key: "k", metaKey: true });
213
+ expect(palette()).toBeInTheDocument();
214
+
215
+ pressChord({ key: "k", metaKey: true });
216
+ expect(palette()).toBeNull();
217
+ });
218
+
219
+ test("Ctrl+K works exactly like Cmd+K (Windows/Linux)", () => {
220
+ render(<DashboardCommandPalette />);
221
+
222
+ pressChord({ key: "k", ctrlKey: true });
223
+ expect(palette()).toBeInTheDocument();
224
+
225
+ pressChord({ key: "k", ctrlKey: true });
226
+ expect(palette()).toBeNull();
227
+ });
228
+
229
+ test("a chord another handler already claimed (defaultPrevented) is ignored", () => {
230
+ render(<DashboardCommandPalette />);
231
+
232
+ /*
233
+ * A capture-phase window listener models "some earlier handler took this
234
+ * chord": it runs before the host's document listener and claims the
235
+ * event, exactly the situation defaultPrevented is checked for.
236
+ */
237
+ const claimChord: (event: KeyboardEvent) => void = (
238
+ event: KeyboardEvent,
239
+ ): void => {
240
+ event.preventDefault();
241
+ };
242
+ window.addEventListener("keydown", claimChord, { capture: true });
243
+
244
+ try {
245
+ pressChord({ key: "k", metaKey: true });
246
+ expect(palette()).toBeNull();
247
+ } finally {
248
+ window.removeEventListener("keydown", claimChord, { capture: true });
249
+ }
250
+
251
+ // And with the claimer gone the same chord opens the palette again.
252
+ pressChord({ key: "k", metaKey: true });
253
+ expect(palette()).toBeInTheDocument();
254
+ });
255
+
256
+ test("extra modifiers on the chord do not open the palette", () => {
257
+ render(<DashboardCommandPalette />);
258
+
259
+ pressChord({ key: "k", metaKey: true, shiftKey: true });
260
+ pressChord({ key: "k", ctrlKey: true, altKey: true });
261
+ pressChord({ key: "k" });
262
+
263
+ expect(palette()).toBeNull();
264
+ });
265
+ });
266
+
267
+ describe("DashboardCommandPalette global toggle event", () => {
268
+ test("the COMMAND_PALETTE_TOGGLE event toggles the palette", () => {
269
+ render(<DashboardCommandPalette />);
270
+ expect(palette()).toBeNull();
271
+
272
+ act((): void => {
273
+ GlobalEvents.dispatchEvent(EventName.COMMAND_PALETTE_TOGGLE);
274
+ });
275
+ expect(palette()).toBeInTheDocument();
276
+
277
+ act((): void => {
278
+ GlobalEvents.dispatchEvent(EventName.COMMAND_PALETTE_TOGGLE);
279
+ });
280
+ expect(palette()).toBeNull();
281
+ });
282
+ });
283
+
284
+ describe("DashboardCommandPalette listener cleanup", () => {
285
+ test("unmounting removes every document keydown listener it added, same references", () => {
286
+ const addSpy: ReturnType<typeof jest.spyOn> = jest.spyOn(
287
+ document,
288
+ "addEventListener",
289
+ );
290
+ const removeSpy: ReturnType<typeof jest.spyOn> = jest.spyOn(
291
+ document,
292
+ "removeEventListener",
293
+ );
294
+
295
+ try {
296
+ const view: ReturnType<typeof render> = render(
297
+ <DashboardCommandPalette />,
298
+ );
299
+
300
+ const addedKeydownListeners: Array<unknown> = addSpy.mock.calls
301
+ .filter((call: Array<unknown>): boolean => {
302
+ return call[0] === "keydown";
303
+ })
304
+ .map((call: Array<unknown>): unknown => {
305
+ return call[1];
306
+ });
307
+
308
+ // The host claims the chord at the document level while mounted.
309
+ expect(addedKeydownListeners.length).toBeGreaterThanOrEqual(1);
310
+
311
+ view.unmount();
312
+
313
+ const removedKeydownListeners: Array<unknown> = removeSpy.mock.calls
314
+ .filter((call: Array<unknown>): boolean => {
315
+ return call[0] === "keydown";
316
+ })
317
+ .map((call: Array<unknown>): unknown => {
318
+ return call[1];
319
+ });
320
+
321
+ /*
322
+ * Every added listener must be removed with the SAME function
323
+ * reference — an inline re-created arrow in the cleanup would leave
324
+ * the original behind and stack a listener per mount.
325
+ */
326
+ for (const listener of addedKeydownListeners) {
327
+ expect(removedKeydownListeners).toContain(listener);
328
+ }
329
+
330
+ // And a chord after unmount reaches nothing.
331
+ pressChord({ key: "k", metaKey: true });
332
+ expect(palette()).toBeNull();
333
+ } finally {
334
+ addSpy.mockRestore();
335
+ removeSpy.mockRestore();
336
+ }
337
+ });
338
+ });
@@ -60,7 +60,7 @@ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
60
60
  * Record MarkdownViewer's props so safeMode remains an asserted part of the
61
61
  * contract even when the Common Jest config replaces its markdown renderer.
62
62
  */
63
- jest.mock("../../../UI/Components/Markdown.tsx/MarkdownViewer", () => {
63
+ jest.mock("../../../UI/Components/Markdown.tsx/LazyMarkdownViewer", () => {
64
64
  return {
65
65
  __esModule: true,
66
66
  default: (props: MarkdownViewerProps): React.ReactElement => {
@@ -51,6 +51,15 @@ const search: SearchFunction = (value: string): void => {
51
51
  });
52
52
  };
53
53
 
54
+ // Every type the catalog actually offers, in the order the picker lists them.
55
+ const catalogTypeValues: Array<string> = categorizedOptions.flatMap(
56
+ (group: CardSelectOptionGroup) => {
57
+ return group.options.map((option: CardSelectOption) => {
58
+ return option.value;
59
+ });
60
+ },
61
+ );
62
+
54
63
  type ShownTypesFunction = () => Array<string>;
55
64
 
56
65
  const shownTypes: ShownTypesFunction = (): Array<string> => {
@@ -231,6 +240,25 @@ describe("Monitor type picker", () => {
231
240
 
232
241
  expect(onChange).toHaveBeenCalledWith(MonitorType.Kubernetes);
233
242
  });
243
+
244
+ /*
245
+ * The e2e suite reaches a folded-away type by typing its MonitorType value
246
+ * into this box and then clicking card-select-option-<value>
247
+ * (selectMonitorTypeCard in E2E/Tests/Dashboard/Helpers/Monitors.ts). That
248
+ * only holds while every type's own value is a search term that finds it,
249
+ * which a renamed title or a reworded description can quietly break — and
250
+ * the only thing that would notice is a full release e2e run.
251
+ */
252
+ test.each(catalogTypeValues)(
253
+ "typing %s finds the card the e2e suite goes on to click",
254
+ (value: string) => {
255
+ renderPicker();
256
+
257
+ search(value);
258
+
259
+ expect(screen.getByTestId(`card-select-option-${value}`)).toBeVisible();
260
+ },
261
+ );
234
262
  });
235
263
 
236
264
  describe("coming back to a form that already has a type", () => {
@@ -0,0 +1,172 @@
1
+ /**
2
+ * UserPush.isCriticalAlertEnabled column contract.
3
+ *
4
+ * This is the one stored preference in the product whose purpose is to DEFEAT
5
+ * a choice the user made with a physical switch on their phone. Everything
6
+ * below pins a property that, quietly changed, either wakes people who did not
7
+ * ask to be woken or - far worse for an on-call product - stops waking people
8
+ * who did.
9
+ *
10
+ * The three "default" mechanisms are separate and easy to confuse:
11
+ * - NEW rows get false from the Postgres column default (@Column default)
12
+ * - EXISTING rows got false from the migration's NOT NULL DEFAULT false
13
+ * - @TableColumn defaultValue is documentation for the generated API schema
14
+ * and forms; it defaults nothing at runtime
15
+ */
16
+
17
+ import UserPush from "../../Models/DatabaseModels/UserPush";
18
+ import { TableColumnMetadata } from "../../Types/Database/TableColumn";
19
+ import TableColumnType from "../../Types/Database/TableColumnType";
20
+ import Permission from "../../Types/Permission";
21
+ import { describe, expect, test } from "@jest/globals";
22
+ import { getMetadataArgsStorage } from "typeorm";
23
+ import { ColumnMetadataArgs } from "typeorm/metadata-args/ColumnMetadataArgs";
24
+ import fs from "fs";
25
+ import path from "path";
26
+
27
+ const COLUMN: string = "isCriticalAlertEnabled";
28
+
29
+ const MIGRATIONS_DIR: string = path.join(
30
+ __dirname,
31
+ "..",
32
+ "..",
33
+ "Server",
34
+ "Infrastructure",
35
+ "Postgres",
36
+ "SchemaMigrations",
37
+ );
38
+
39
+ const MIGRATION_CLASS: string = "MigrationName1787156982416";
40
+
41
+ const MIGRATION_PATH: string = path.join(
42
+ MIGRATIONS_DIR,
43
+ "1787156982416-MigrationName.ts",
44
+ );
45
+
46
+ function metadata(): TableColumnMetadata {
47
+ return new UserPush().getTableColumnMetadata(COLUMN);
48
+ }
49
+
50
+ function typeOrmColumn(): ColumnMetadataArgs | undefined {
51
+ return getMetadataArgsStorage().columns.find((column: ColumnMetadataArgs) => {
52
+ return column.target === UserPush && column.propertyName === COLUMN;
53
+ });
54
+ }
55
+
56
+ describe("UserPush.isCriticalAlertEnabled", () => {
57
+ test("exists as a boolean column", () => {
58
+ expect(metadata()).toBeDefined();
59
+ expect(metadata().type).toBe(TableColumnType.Boolean);
60
+ });
61
+
62
+ test("a newly registered device does NOT override silent mode", () => {
63
+ /*
64
+ * The single most important assertion in this file. Overriding a silenced
65
+ * phone is opted into, never inherited: a responder who installs the app
66
+ * has not asked to be woken by it, and a default of true would make every
67
+ * existing user's phone start ringing through Do Not Disturb on upgrade.
68
+ */
69
+ expect(typeOrmColumn()).toBeDefined();
70
+ expect(typeOrmColumn()?.options.default).toBe(false);
71
+ });
72
+
73
+ test("every device that existed before this feature was backfilled as off", () => {
74
+ const migration: string = fs.readFileSync(MIGRATION_PATH, "utf8");
75
+
76
+ expect(migration).toContain('ALTER TABLE "UserPush"');
77
+ expect(migration).toContain(
78
+ `ADD "${COLUMN}" boolean NOT NULL DEFAULT false`,
79
+ );
80
+ });
81
+
82
+ test("the migration is registered, so the column actually exists at runtime", () => {
83
+ /*
84
+ * A migration file missing from Index.ts never runs. The column would then
85
+ * be absent from Postgres while every select in the paging path asks for
86
+ * it, which fails the query that sends the page.
87
+ */
88
+ const index: string = fs.readFileSync(
89
+ path.join(MIGRATIONS_DIR, "Index.ts"),
90
+ "utf8",
91
+ );
92
+
93
+ // Imported AND listed in the exported array - the import alone does nothing.
94
+ expect(index.match(new RegExp(MIGRATION_CLASS, "g"))?.length).toBe(2);
95
+ });
96
+
97
+ test("the migration's down() removes the column", () => {
98
+ const migration: string = fs.readFileSync(MIGRATION_PATH, "utf8");
99
+
100
+ expect(migration).toContain(
101
+ `ALTER TABLE "UserPush" DROP COLUMN "${COLUMN}"`,
102
+ );
103
+ });
104
+
105
+ test("is a default-value column, so existing create calls keep working", () => {
106
+ expect(new UserPush().isDefaultValueColumn(COLUMN)).toBe(true);
107
+ expect(metadata().required).toBeFalsy();
108
+ });
109
+
110
+ test("is documented as defaulting to off", () => {
111
+ expect(metadata().defaultValue).toBe(false);
112
+ });
113
+ });
114
+
115
+ describe("UserPush.isCriticalAlertEnabled access control", () => {
116
+ /*
117
+ * UserPush is an owner-only table: its table-level `read` names
118
+ * Permission.CurrentUser and nothing else, which is what scopes every read
119
+ * to the caller's own rows. A new column has to keep that shape or it
120
+ * becomes the exception that widens the table.
121
+ */
122
+ test("is readable only by the responder it belongs to", () => {
123
+ const read: Array<Permission> | undefined =
124
+ new UserPush().getColumnAccessControlFor(COLUMN)?.read;
125
+
126
+ expect(read).toEqual([Permission.CurrentUser]);
127
+ });
128
+
129
+ test("is settable at registration by the responder", () => {
130
+ const create: Array<Permission> | undefined =
131
+ new UserPush().getColumnAccessControlFor(COLUMN)?.create;
132
+
133
+ expect(create).toEqual([Permission.CurrentUser]);
134
+ });
135
+
136
+ test("cannot be written through the generic CRUD update surface", () => {
137
+ /*
138
+ * Every column on this model has an empty update list; writes go through
139
+ * the dedicated routes that check row ownership first and then act as
140
+ * root. Granting update here would let the flag be flipped by any path
141
+ * that can PUT the model, which is a wider surface than "the phone that
142
+ * owns this row".
143
+ */
144
+ const update: Array<Permission> | undefined =
145
+ new UserPush().getColumnAccessControlFor(COLUMN)?.update;
146
+
147
+ expect(update).toEqual([]);
148
+ });
149
+
150
+ test("does not widen the table's owner-only read scope", () => {
151
+ /*
152
+ * isAccessGrantedOnlyByCurrentUser is true exactly while the TABLE read
153
+ * list holds nothing but CurrentUser, and that is what stamps
154
+ * `userId = me` onto every read of this table. Adding a column must not
155
+ * disturb it.
156
+ */
157
+ expect(new UserPush().getReadPermissions()).toEqual([
158
+ Permission.CurrentUser,
159
+ ]);
160
+ });
161
+
162
+ test("is not marked readable through relation queries", () => {
163
+ /*
164
+ * canReadOnRelationQuery makes a column readable from a nested select on a
165
+ * model whose own read is admin-wide, skipping this table's column check
166
+ * entirely. isVerified - the column this one sits beside and is read
167
+ * alongside - does not set it, and neither does this: the paging path
168
+ * reads both as root, so nothing needs the flag.
169
+ */
170
+ expect(metadata().canReadOnRelationQuery).toBeFalsy();
171
+ });
172
+ });