@oneuptime/common 12.0.12 → 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 (596) hide show
  1. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +32 -5
  2. package/Models/DatabaseModels/NetworkDevice.ts +64 -0
  3. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +14 -0
  4. package/Models/DatabaseModels/StatusPage.ts +59 -0
  5. package/Models/DatabaseModels/StatusPageOidc.ts +2 -0
  6. package/Models/DatabaseModels/UserCall.ts +94 -3
  7. package/Models/DatabaseModels/UserEmail.ts +94 -3
  8. package/Models/DatabaseModels/UserIncomingCallNumber.ts +94 -3
  9. package/Models/DatabaseModels/UserPush.ts +37 -0
  10. package/Models/DatabaseModels/UserSMS.ts +94 -3
  11. package/Models/DatabaseModels/UserWhatsApp.ts +93 -2
  12. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -2
  13. package/Server/API/AIChatAPI.ts +55 -56
  14. package/Server/API/BaseAPI.ts +79 -14
  15. package/Server/API/CommonAPI.ts +89 -0
  16. package/Server/API/MicrosoftTeamsAPI.ts +20 -9
  17. package/Server/API/SlackAPI.ts +13 -10
  18. package/Server/API/StatusPageAPI.ts +2197 -2128
  19. package/Server/API/TelemetryAPI.ts +72 -3
  20. package/Server/API/UserCallAPI.ts +53 -45
  21. package/Server/API/UserEmailAPI.ts +53 -44
  22. package/Server/API/UserIncomingCallNumberAPI.ts +48 -38
  23. package/Server/API/UserNotificationMethodAdminAPI.ts +481 -0
  24. package/Server/API/UserPushAPI.ts +126 -2
  25. package/Server/API/UserSmsAPI.ts +53 -44
  26. package/Server/API/UserWhatsAppAPI.ts +53 -50
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.ts +154 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.ts +17 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.ts +30 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.ts +47 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.ts +45 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  33. package/Server/Middleware/UserAuthorization.ts +11 -2
  34. package/Server/Middleware/VerificationCodeRateLimit.ts +586 -0
  35. package/Server/Services/AnalyticsDatabaseService.ts +169 -0
  36. package/Server/Services/ApiKeyPermissionService.ts +116 -2
  37. package/Server/Services/DatabaseService.ts +118 -6
  38. package/Server/Services/LogAggregationService.ts +39 -0
  39. package/Server/Services/LogService.ts +21 -0
  40. package/Server/Services/NetworkSiteService.ts +12 -0
  41. package/Server/Services/PushNotificationService.ts +127 -12
  42. package/Server/Services/SpanService.ts +21 -0
  43. package/Server/Services/TeamMemberService.ts +53 -13
  44. package/Server/Services/TraceAggregationService.ts +15 -0
  45. package/Server/Services/UserCallService.ts +55 -24
  46. package/Server/Services/UserEmailService.ts +83 -17
  47. package/Server/Services/UserIncomingCallNumberService.ts +49 -85
  48. package/Server/Services/UserNotificationMethodAdminService.ts +1527 -0
  49. package/Server/Services/UserNotificationRuleService.ts +26 -0
  50. package/Server/Services/UserPushService.ts +89 -0
  51. package/Server/Services/UserSmsService.ts +50 -17
  52. package/Server/Services/UserWhatsAppService.ts +48 -15
  53. package/Server/Services/WorkspaceNotificationRuleService.ts +172 -220
  54. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
  55. package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -16
  56. package/Server/Types/Database/QueryHelper.ts +30 -0
  57. package/Server/Utils/APIKey/AccessPermission.ts +16 -40
  58. package/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.ts +59 -0
  59. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +144 -0
  60. package/Server/Utils/ChannelVerification.ts +510 -0
  61. package/Server/Utils/LogRedaction.ts +576 -0
  62. package/Server/Utils/Logger.ts +123 -46
  63. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +13 -16
  64. package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +94 -23
  65. package/Server/Utils/Monitor/MonitorAlert.ts +24 -21
  66. package/Server/Utils/Monitor/MonitorIncident.ts +21 -18
  67. package/Server/Utils/Monitor/MonitorResource.ts +29 -9
  68. package/Server/Utils/Monitor/MonitorResourceContext.ts +107 -0
  69. package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +442 -0
  70. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +28 -7
  71. package/Server/Utils/Monitor/SeriesResourceLabels.ts +3 -3
  72. package/Server/Utils/Monitor/SeriesResourceLinker.ts +96 -28
  73. package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +56 -10
  74. package/Server/Utils/StartServer.ts +30 -9
  75. package/Server/Utils/StatusPageSearchEngineIndexing.ts +33 -0
  76. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +441 -0
  77. package/Server/Utils/TotpAuth.ts +137 -9
  78. package/Server/Utils/UserRegistrationToken.ts +182 -0
  79. package/Server/Utils/VerificationCode.ts +134 -0
  80. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +488 -46
  81. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +173 -94
  82. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +1151 -0
  83. package/Tests/App/Dashboard/AdminUserOnCallPages.test.tsx +905 -0
  84. package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +338 -0
  85. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1 -1
  86. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +328 -0
  87. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +130 -0
  88. package/Tests/Models/DatabaseModels/DatabaseBaseModelToJSONObjectCache.test.ts +180 -0
  89. package/Tests/Models/StatusPageEnableSearchEngineIndexing.test.ts +157 -0
  90. package/Tests/Models/UserPushCriticalAlertColumn.test.ts +172 -0
  91. package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +23 -1
  92. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +785 -0
  93. package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +21 -8
  94. package/Tests/Server/API/BaseAPIGetListParallel.test.ts +519 -0
  95. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +290 -0
  96. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +7 -1
  97. package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +543 -0
  98. package/Tests/Server/API/StatusPageOverviewCache.test.ts +474 -0
  99. package/Tests/Server/API/StatusPageSeoSearchEngineIndexing.test.ts +189 -0
  100. package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +108 -18
  101. package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +963 -0
  102. package/Tests/Server/API/UserPushCriticalAlertsApi.test.ts +114 -0
  103. package/Tests/Server/API/UserSmsApi.test.ts +107 -14
  104. package/Tests/Server/API/UserTotpAuthAPI.test.ts +427 -0
  105. package/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts +158 -0
  106. package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +9 -60
  107. package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +315 -0
  108. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +24 -15
  109. package/Tests/Server/Middleware/UserAuthorization.test.ts +79 -0
  110. package/Tests/Server/Middleware/VerificationCodeRateLimit.test.ts +775 -0
  111. package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +280 -0
  112. package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +33 -13
  113. package/Tests/Server/Services/AnalyticsDatabaseSortKeyBoundary.test.ts +658 -0
  114. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +347 -0
  115. package/Tests/Server/Services/CriticalOnCallAlertDelivery.test.ts +458 -0
  116. package/Tests/Server/Services/CriticalPushAlertPayload.test.ts +301 -0
  117. package/Tests/Server/Services/DatabaseServiceAtomicIncrement.test.ts +143 -0
  118. package/Tests/Server/Services/DatabaseServiceUpdateDebugLogging.test.ts +282 -0
  119. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1 -0
  120. package/Tests/Server/Services/LogAggregationScanMemory.test.ts +421 -0
  121. package/Tests/Server/Services/LogAggregationService.test.ts +2 -2
  122. package/Tests/Server/Services/NetworkSiteService.test.ts +56 -2
  123. package/Tests/Server/Services/NotificationChannelCodeIssuance.test.ts +401 -0
  124. package/Tests/Server/Services/PushNotificationDeliveryOptions.test.ts +204 -0
  125. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +21 -1
  126. package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +290 -0
  127. package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +267 -0
  128. package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +948 -0
  129. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1 -0
  130. package/Tests/Server/Services/UserPushCriticalAlertToggle.test.ts +255 -0
  131. package/Tests/Server/Services/UserTotpAuthEnrolment.test.ts +218 -0
  132. package/Tests/Server/Services/WorkspaceNotificationRuleTestRuleChannels.test.ts +702 -0
  133. package/Tests/Server/TestingUtils/AuthenticatorApp.ts +248 -0
  134. package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +165 -0
  135. package/Tests/Server/Types/Database/Permissions/NotificationChannelVerificationColumns.test.ts +135 -0
  136. package/Tests/Server/Types/Database/Permissions/OnCallScheduleRelationSelect.test.ts +504 -0
  137. package/Tests/Server/Types/Database/QueryHelperFindWithSameTextAnyOf.test.ts +91 -0
  138. package/Tests/Server/Types/Workflow/Components/JsonToText.test.ts +384 -0
  139. package/Tests/Server/Types/Workflow/Components/MergeJson.test.ts +403 -0
  140. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +48 -36
  141. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +213 -0
  142. package/Tests/Server/Utils/Browser.test.ts +162 -0
  143. package/Tests/Server/Utils/ChannelVerification.test.ts +689 -0
  144. package/Tests/Server/Utils/Express.test.ts +371 -0
  145. package/Tests/Server/Utils/LogRedaction.test.ts +415 -0
  146. package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +245 -0
  147. package/Tests/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.test.ts +707 -0
  148. package/Tests/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.test.ts +698 -0
  149. package/Tests/Server/Utils/Monitor/Criteria/IncomingEmailBodyCriteria.test.ts +243 -0
  150. package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestBodyCriteria.test.ts +278 -0
  151. package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +374 -4
  152. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +160 -20
  153. package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +13 -8
  154. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +162 -18
  155. package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +349 -0
  156. package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +455 -0
  157. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +690 -0
  158. package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +7 -2
  159. package/Tests/Server/Utils/Monitor/NetworkDeviceReachabilityRoundTrip.test.ts +369 -0
  160. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +86 -8
  161. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +92 -18
  162. package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +64 -0
  163. package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +267 -0
  164. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCacheStore.test.ts +207 -0
  165. package/Tests/Server/Utils/StartServerBodyVerify.test.ts +335 -0
  166. package/Tests/Server/Utils/StatusPageSearchEngineIndexing.test.ts +60 -0
  167. package/Tests/Server/Utils/Telemetry/OneuptimeLabel.test.ts +439 -0
  168. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +435 -0
  169. package/Tests/Server/Utils/TotpAuth.test.ts +719 -0
  170. package/Tests/Server/Utils/UserRegistrationToken.test.ts +322 -0
  171. package/Tests/Server/Utils/VerificationCode.test.ts +296 -0
  172. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +607 -62
  173. package/Tests/Server/Utils/Workspace/MicrosoftTeamsInstalledTeamIdSpace.test.ts +778 -0
  174. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +44 -10
  175. package/Tests/Types/API/HostnameFromAuthority.test.ts +164 -0
  176. package/Tests/Types/AutoRemediation/AutoRemediationSuggestionStatus.test.ts +192 -0
  177. package/Tests/Types/Call/CallRequest.test.ts +189 -0
  178. package/Tests/Types/Dashboard/DashboardSize.test.ts +226 -0
  179. package/Tests/Types/Database/AccessControl/ColumnAccessControlCache.test.ts +344 -0
  180. package/Tests/Types/Database/DatabasePropertyFindOperator.test.ts +518 -0
  181. package/Tests/Types/Database/TableColumnMetadataCache.test.ts +286 -0
  182. package/Tests/Types/Incident/IncidentSlaStatus.test.ts +191 -0
  183. package/Tests/Types/Metrics/MetricDashboardMetricType.test.ts +278 -0
  184. package/Tests/Types/Metrics/MetricPipelineRuleType.test.ts +517 -0
  185. package/Tests/Types/Monitor/IncomingMonitorDefaultCriteria.test.ts +470 -0
  186. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +6 -4
  187. package/Tests/Types/Monitor/MonitorStep.test.ts +100 -0
  188. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +360 -0
  189. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +262 -5
  190. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
  191. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
  192. package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +905 -0
  193. package/Tests/Types/Service/ServiceLanguage.test.ts +255 -0
  194. package/Tests/Types/StatusPage/SearchEngineIndexing.test.ts +86 -0
  195. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +254 -0
  196. package/Tests/Types/TextRandomGeneration.test.ts +211 -0
  197. package/Tests/UI/Components/Button.test.tsx +175 -1
  198. package/Tests/UI/Components/CardSelect.test.tsx +1021 -0
  199. package/Tests/UI/Components/CodeBlockLanguages.test.tsx +236 -0
  200. package/Tests/UI/Components/CommandPalette/CommandPalette.test.tsx +568 -0
  201. package/Tests/UI/Components/CommandPalette/CommandPaletteKeyboard.test.tsx +239 -0
  202. package/Tests/UI/Components/CommandPalette/CommandPaletteProviders.test.tsx +400 -0
  203. package/Tests/UI/Components/CommandPalette/PaletteFilter.test.ts +234 -0
  204. package/Tests/UI/Components/CommandPalette/RecentCommands.test.ts +97 -0
  205. package/Tests/UI/Components/CountModelSideMenuItemGuard.test.tsx +198 -0
  206. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +1 -1
  207. package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +267 -0
  208. package/Tests/UI/Components/List.test.tsx +9 -2
  209. package/Tests/UI/Components/ListLoadingStates.test.tsx +173 -0
  210. package/Tests/UI/Components/MarkdownLazy.test.tsx +113 -0
  211. package/Tests/UI/Components/MarkdownMermaidRetry.test.tsx +110 -0
  212. package/Tests/UI/Components/MasterPage.test.tsx +36 -1
  213. package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +8 -0
  214. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +692 -0
  215. package/Tests/UI/Components/MoreMenuMotion.test.tsx +118 -0
  216. package/Tests/UI/Components/NavBarCommandKGating.test.tsx +178 -0
  217. package/Tests/UI/Components/OrderedStatesList.test.tsx +19 -2
  218. package/Tests/UI/Components/SideOverMotion.test.tsx +109 -0
  219. package/Tests/UI/Components/Skeleton.test.tsx +71 -0
  220. package/Tests/UI/Components/TableLoadingStates.test.tsx +279 -0
  221. package/Tests/UI/Components/Tabs.test.tsx +24 -0
  222. package/Tests/UI/Components/Toast.test.tsx +130 -7
  223. package/Tests/UI/Components/ToastStacking.test.tsx +198 -0
  224. package/Tests/UI/Utils/Dropdown.test.ts +423 -0
  225. package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +122 -0
  226. package/Tests/UI/Utils/ModelListCache.test.ts +338 -0
  227. package/Tests/UI/Utils/ProjectListCacheInvalidation.test.ts +225 -0
  228. package/Tests/Utils/API.test.ts +16 -2
  229. package/Tests/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.test.ts +347 -0
  230. package/Tests/Utils/Dashboard/Components/DashboardListSharedArgs.test.ts +259 -0
  231. package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +466 -0
  232. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +66 -1
  233. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +115 -6
  234. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +610 -0
  235. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +114 -45
  236. package/Tests/Utils/Rum/UrlScrubberSegments.test.ts +362 -0
  237. package/Types/API/Hostname.ts +79 -0
  238. package/Types/Database/AccessControl/ColumnAccessControl.ts +33 -11
  239. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +33 -11
  240. package/Types/Database/DatabaseProperty.ts +38 -0
  241. package/Types/Database/TableColumn.ts +34 -7
  242. package/Types/Email/EmailTemplateType.ts +1 -0
  243. package/Types/Events/Recurring.ts +16 -1
  244. package/Types/Monitor/MonitorCriteriaInstance.ts +41 -20
  245. package/Types/Monitor/MonitorStep.ts +13 -1
  246. package/Types/Monitor/MonitorType.ts +345 -40
  247. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +131 -8
  248. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +48 -8
  249. package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +43 -0
  250. package/Types/Monitor/ServiceAlertTemplates.ts +1352 -0
  251. package/Types/Permission.ts +35 -0
  252. package/Types/PushNotification/AndroidNotificationChannel.ts +26 -0
  253. package/Types/PushNotification/PushNotificationMessage.ts +15 -0
  254. package/Types/PushNotification/PushNotificationRequest.ts +8 -16
  255. package/Types/Service/ServiceLanguage.ts +144 -0
  256. package/Types/StatusPage/SearchEngineIndexing.ts +61 -0
  257. package/Types/Telemetry/ResourceEntityFacet.ts +211 -0
  258. package/Types/Text.ts +111 -19
  259. package/UI/Components/Button/Button.tsx +27 -14
  260. package/UI/Components/CardSelect/CardSelect.tsx +714 -105
  261. package/UI/Components/CodeBlock/CodeBlock.tsx +54 -7
  262. package/UI/Components/CodeBlock/LanguageRegistry.ts +103 -0
  263. package/UI/Components/CommandPalette/CommandPalette.tsx +790 -0
  264. package/UI/Components/CommandPalette/PaletteFilter.ts +196 -0
  265. package/UI/Components/CommandPalette/PaletteRow.tsx +173 -0
  266. package/UI/Components/CommandPalette/RecentCommands.ts +57 -0
  267. package/UI/Components/CommandPalette/Types.ts +49 -0
  268. package/UI/Components/CommandPalette/UseProviderSearch.ts +129 -0
  269. package/UI/Components/Dropdown/Dropdown.tsx +6 -1
  270. package/UI/Components/EmptyState/EmptyState.tsx +8 -1
  271. package/UI/Components/Feed/FeedItem.tsx +1 -1
  272. package/UI/Components/Footer/Footer.tsx +32 -6
  273. package/UI/Components/Forms/Fields/FormField.tsx +3 -0
  274. package/UI/Components/Forms/Types/Field.ts +8 -0
  275. package/UI/Components/List/List.tsx +37 -5
  276. package/UI/Components/List/ListSkeleton.tsx +54 -0
  277. package/UI/Components/Loader/PageLoader.tsx +29 -8
  278. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +26 -4
  279. package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +23 -2
  280. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +71 -26
  281. package/UI/Components/MasterPage/MasterPage.tsx +24 -11
  282. package/UI/Components/Modal/Modal.tsx +2 -2
  283. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  284. package/UI/Components/ModelTable/useCustomFieldColumns.ts +11 -5
  285. package/UI/Components/MoreMenu/MoreMenu.tsx +39 -1
  286. package/UI/Components/Navbar/NavBar.tsx +14 -1
  287. package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +50 -5
  288. package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +40 -1
  289. package/UI/Components/SideOver/SideOver.tsx +37 -2
  290. package/UI/Components/Skeleton/Skeleton.tsx +53 -0
  291. package/UI/Components/Table/Table.tsx +74 -44
  292. package/UI/Components/Table/TableSkeletonRows.tsx +141 -0
  293. package/UI/Components/Tabs/Tab.tsx +1 -1
  294. package/UI/Components/Toast/Toast.tsx +118 -53
  295. package/UI/Components/Toast/ToastInit.tsx +82 -32
  296. package/UI/Styles/Theme.css +40 -0
  297. package/UI/Utils/ModelAPI/ModelAPI.ts +20 -10
  298. package/UI/Utils/ModelListCache.ts +188 -0
  299. package/UI/Utils/Project.ts +29 -0
  300. package/Utils/API.ts +6 -1
  301. package/Utils/Monitor/MonitorMetricType.ts +16 -1
  302. package/Utils/Monitor/NetworkTopologyUtil.ts +60 -8
  303. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +262 -0
  304. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +41 -24
  305. package/Utils/Telemetry/CrossSignalScope.ts +75 -4
  306. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +20 -4
  307. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  308. package/build/dist/Models/DatabaseModels/NetworkDevice.js +66 -0
  309. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  310. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +14 -0
  311. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  312. package/build/dist/Models/DatabaseModels/StatusPage.js +60 -0
  313. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  314. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +2 -0
  315. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  316. package/build/dist/Models/DatabaseModels/UserCall.js +101 -3
  317. package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
  318. package/build/dist/Models/DatabaseModels/UserEmail.js +101 -3
  319. package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
  320. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +101 -3
  321. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -1
  322. package/build/dist/Models/DatabaseModels/UserPush.js +38 -0
  323. package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
  324. package/build/dist/Models/DatabaseModels/UserSMS.js +101 -3
  325. package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
  326. package/build/dist/Models/DatabaseModels/UserWhatsApp.js +100 -2
  327. package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
  328. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  329. package/build/dist/Server/API/AIChatAPI.js +48 -35
  330. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  331. package/build/dist/Server/API/BaseAPI.js +69 -13
  332. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  333. package/build/dist/Server/API/CommonAPI.js +59 -0
  334. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  335. package/build/dist/Server/API/MicrosoftTeamsAPI.js +20 -6
  336. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  337. package/build/dist/Server/API/SlackAPI.js +13 -10
  338. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  339. package/build/dist/Server/API/StatusPageAPI.js +745 -673
  340. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  341. package/build/dist/Server/API/TelemetryAPI.js +34 -3
  342. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  343. package/build/dist/Server/API/UserCallAPI.js +42 -38
  344. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  345. package/build/dist/Server/API/UserEmailAPI.js +42 -38
  346. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  347. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +37 -32
  348. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
  349. package/build/dist/Server/API/UserNotificationMethodAdminAPI.js +341 -0
  350. package/build/dist/Server/API/UserNotificationMethodAdminAPI.js.map +1 -0
  351. package/build/dist/Server/API/UserPushAPI.js +95 -2
  352. package/build/dist/Server/API/UserPushAPI.js.map +1 -1
  353. package/build/dist/Server/API/UserSmsAPI.js +42 -38
  354. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  355. package/build/dist/Server/API/UserWhatsAppAPI.js +42 -40
  356. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  357. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js +89 -0
  358. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js.map +1 -0
  359. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js +12 -0
  360. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js.map +1 -0
  361. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js +23 -0
  362. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js.map +1 -0
  363. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js +34 -0
  364. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js.map +1 -0
  365. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js +40 -0
  366. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js.map +1 -0
  367. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  368. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  369. package/build/dist/Server/Middleware/UserAuthorization.js +6 -2
  370. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  371. package/build/dist/Server/Middleware/VerificationCodeRateLimit.js +393 -0
  372. package/build/dist/Server/Middleware/VerificationCodeRateLimit.js.map +1 -0
  373. package/build/dist/Server/Services/AnalyticsDatabaseService.js +136 -0
  374. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  375. package/build/dist/Server/Services/ApiKeyPermissionService.js +90 -1
  376. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  377. package/build/dist/Server/Services/DatabaseService.js +89 -6
  378. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  379. package/build/dist/Server/Services/LogAggregationService.js +7 -0
  380. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  381. package/build/dist/Server/Services/LogService.js +16 -0
  382. package/build/dist/Server/Services/LogService.js.map +1 -1
  383. package/build/dist/Server/Services/NetworkSiteService.js +12 -0
  384. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  385. package/build/dist/Server/Services/PushNotificationService.js +69 -30
  386. package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
  387. package/build/dist/Server/Services/SpanService.js +16 -0
  388. package/build/dist/Server/Services/SpanService.js.map +1 -1
  389. package/build/dist/Server/Services/TeamMemberService.js +43 -7
  390. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  391. package/build/dist/Server/Services/TraceAggregationService.js +2 -0
  392. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  393. package/build/dist/Server/Services/UserCallService.js +54 -22
  394. package/build/dist/Server/Services/UserCallService.js.map +1 -1
  395. package/build/dist/Server/Services/UserEmailService.js +78 -17
  396. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  397. package/build/dist/Server/Services/UserIncomingCallNumberService.js +45 -74
  398. package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -1
  399. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1117 -0
  400. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -0
  401. package/build/dist/Server/Services/UserNotificationRuleService.js +20 -0
  402. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  403. package/build/dist/Server/Services/UserPushService.js +77 -0
  404. package/build/dist/Server/Services/UserPushService.js.map +1 -1
  405. package/build/dist/Server/Services/UserSmsService.js +50 -17
  406. package/build/dist/Server/Services/UserSmsService.js.map +1 -1
  407. package/build/dist/Server/Services/UserWhatsAppService.js +48 -15
  408. package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
  409. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +137 -164
  410. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  411. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
  412. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  413. package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +21 -13
  414. package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
  415. package/build/dist/Server/Types/Database/QueryHelper.js +27 -0
  416. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  417. package/build/dist/Server/Utils/APIKey/AccessPermission.js +9 -32
  418. package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
  419. package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js +46 -0
  420. package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js.map +1 -1
  421. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +87 -0
  422. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  423. package/build/dist/Server/Utils/ChannelVerification.js +348 -0
  424. package/build/dist/Server/Utils/ChannelVerification.js.map +1 -0
  425. package/build/dist/Server/Utils/LogRedaction.js +449 -0
  426. package/build/dist/Server/Utils/LogRedaction.js.map +1 -0
  427. package/build/dist/Server/Utils/Logger.js +98 -45
  428. package/build/dist/Server/Utils/Logger.js.map +1 -1
  429. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +13 -12
  430. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  431. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +65 -13
  432. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
  433. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +20 -17
  434. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  435. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +17 -14
  436. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  437. package/build/dist/Server/Utils/Monitor/MonitorResource.js +20 -3
  438. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  439. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +95 -0
  440. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -0
  441. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +313 -0
  442. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -0
  443. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +27 -7
  444. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  445. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +3 -3
  446. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +67 -26
  447. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
  448. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +29 -10
  449. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -1
  450. package/build/dist/Server/Utils/StartServer.js +10 -7
  451. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  452. package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js +24 -0
  453. package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js.map +1 -0
  454. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +311 -0
  455. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -0
  456. package/build/dist/Server/Utils/TotpAuth.js +127 -8
  457. package/build/dist/Server/Utils/TotpAuth.js.map +1 -1
  458. package/build/dist/Server/Utils/UserRegistrationToken.js +170 -0
  459. package/build/dist/Server/Utils/UserRegistrationToken.js.map +1 -0
  460. package/build/dist/Server/Utils/VerificationCode.js +120 -0
  461. package/build/dist/Server/Utils/VerificationCode.js.map +1 -0
  462. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +366 -37
  463. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  464. package/build/dist/Types/API/Hostname.js +63 -0
  465. package/build/dist/Types/API/Hostname.js.map +1 -1
  466. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +20 -6
  467. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  468. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +20 -6
  469. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  470. package/build/dist/Types/Database/DatabaseProperty.js +38 -0
  471. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  472. package/build/dist/Types/Database/TableColumn.js +24 -6
  473. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  474. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  475. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  476. package/build/dist/Types/Events/Recurring.js +13 -1
  477. package/build/dist/Types/Events/Recurring.js.map +1 -1
  478. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +42 -21
  479. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  480. package/build/dist/Types/Monitor/MonitorStep.js +9 -1
  481. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  482. package/build/dist/Types/Monitor/MonitorType.js +330 -31
  483. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  484. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +77 -5
  485. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  486. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +18 -6
  487. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  488. package/build/dist/Types/Monitor/ServiceAlertTemplates.js +1028 -0
  489. package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -0
  490. package/build/dist/Types/Permission.js +33 -0
  491. package/build/dist/Types/Permission.js.map +1 -1
  492. package/build/dist/Types/PushNotification/AndroidNotificationChannel.js +27 -0
  493. package/build/dist/Types/PushNotification/AndroidNotificationChannel.js.map +1 -0
  494. package/build/dist/Types/Service/ServiceLanguage.js +96 -0
  495. package/build/dist/Types/Service/ServiceLanguage.js.map +1 -0
  496. package/build/dist/Types/StatusPage/SearchEngineIndexing.js +55 -0
  497. package/build/dist/Types/StatusPage/SearchEngineIndexing.js.map +1 -0
  498. package/build/dist/Types/Telemetry/ResourceEntityFacet.js +156 -0
  499. package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -0
  500. package/build/dist/Types/Text.js +82 -17
  501. package/build/dist/Types/Text.js.map +1 -1
  502. package/build/dist/UI/Components/Button/Button.js +22 -14
  503. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  504. package/build/dist/UI/Components/CardSelect/CardSelect.js +360 -40
  505. package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
  506. package/build/dist/UI/Components/CodeBlock/CodeBlock.js +35 -3
  507. package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
  508. package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js +57 -0
  509. package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js.map +1 -0
  510. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +439 -0
  511. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -0
  512. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js +135 -0
  513. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js.map +1 -0
  514. package/build/dist/UI/Components/CommandPalette/PaletteRow.js +83 -0
  515. package/build/dist/UI/Components/CommandPalette/PaletteRow.js.map +1 -0
  516. package/build/dist/UI/Components/CommandPalette/RecentCommands.js +47 -0
  517. package/build/dist/UI/Components/CommandPalette/RecentCommands.js.map +1 -0
  518. package/build/dist/UI/Components/CommandPalette/Types.js +2 -0
  519. package/build/dist/UI/Components/CommandPalette/Types.js.map +1 -0
  520. package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js +88 -0
  521. package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js.map +1 -0
  522. package/build/dist/UI/Components/Dropdown/Dropdown.js +6 -1
  523. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  524. package/build/dist/UI/Components/EmptyState/EmptyState.js +1 -1
  525. package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
  526. package/build/dist/UI/Components/Feed/FeedItem.js +1 -1
  527. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  528. package/build/dist/UI/Components/Footer/Footer.js +7 -4
  529. package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
  530. package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
  531. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  532. package/build/dist/UI/Components/List/List.js +19 -5
  533. package/build/dist/UI/Components/List/List.js.map +1 -1
  534. package/build/dist/UI/Components/List/ListSkeleton.js +21 -0
  535. package/build/dist/UI/Components/List/ListSkeleton.js.map +1 -0
  536. package/build/dist/UI/Components/Loader/PageLoader.js +15 -5
  537. package/build/dist/UI/Components/Loader/PageLoader.js.map +1 -1
  538. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +16 -3
  539. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  540. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js +13 -1
  541. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
  542. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +52 -25
  543. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  544. package/build/dist/UI/Components/MasterPage/MasterPage.js +10 -2
  545. package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
  546. package/build/dist/UI/Components/Modal/Modal.js +2 -2
  547. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  548. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  549. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +9 -2
  550. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
  551. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +32 -1
  552. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  553. package/build/dist/UI/Components/Navbar/NavBar.js +5 -1
  554. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  555. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +29 -5
  556. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
  557. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +23 -1
  558. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
  559. package/build/dist/UI/Components/SideOver/SideOver.js +23 -2
  560. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  561. package/build/dist/UI/Components/Skeleton/Skeleton.js +23 -0
  562. package/build/dist/UI/Components/Skeleton/Skeleton.js.map +1 -0
  563. package/build/dist/UI/Components/Table/Table.js +35 -24
  564. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  565. package/build/dist/UI/Components/Table/TableSkeletonRows.js +52 -0
  566. package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -0
  567. package/build/dist/UI/Components/Tabs/Tab.js +1 -1
  568. package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
  569. package/build/dist/UI/Components/Toast/Toast.js +77 -23
  570. package/build/dist/UI/Components/Toast/Toast.js.map +1 -1
  571. package/build/dist/UI/Components/Toast/ToastInit.js +37 -15
  572. package/build/dist/UI/Components/Toast/ToastInit.js.map +1 -1
  573. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -9
  574. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  575. package/build/dist/UI/Utils/ModelListCache.js +126 -0
  576. package/build/dist/UI/Utils/ModelListCache.js.map +1 -0
  577. package/build/dist/UI/Utils/Project.js +24 -1
  578. package/build/dist/UI/Utils/Project.js.map +1 -1
  579. package/build/dist/Utils/API.js +6 -1
  580. package/build/dist/Utils/API.js.map +1 -1
  581. package/build/dist/Utils/Monitor/MonitorMetricType.js +13 -1
  582. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  583. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +34 -7
  584. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  585. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +177 -0
  586. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -0
  587. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +23 -27
  588. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  589. package/build/dist/Utils/Telemetry/CrossSignalScope.js +44 -4
  590. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  591. package/jest.config.json +1 -1
  592. package/package.json +2 -3
  593. package/Server/Utils/Monitor/MonitorClusterContext.ts +0 -182
  594. package/Tests/__mocks__/otpauth.js +0 -30
  595. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +0 -141
  596. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +0 -1
@@ -26,6 +26,7 @@ import UserPush from "../../Models/DatabaseModels/UserPush";
26
26
  import PushNotificationLog from "../../Models/DatabaseModels/PushNotificationLog";
27
27
  import PushNotificationLogService from "./PushNotificationLogService";
28
28
  import PushStatus from "../../Types/PushNotification/PushStatus";
29
+ import AndroidNotificationChannel from "../../Types/PushNotification/AndroidNotificationChannel";
29
30
 
30
31
  /*
31
32
  * The push services the browsers actually use. A Web Push subscription is a
@@ -67,6 +68,43 @@ export interface PushNotificationOptions {
67
68
  teamId?: ObjectID | undefined;
68
69
  }
69
70
 
71
+ /*
72
+ * What Expo needs to be told for a notification to ring through a silenced
73
+ * handset. The two platforms disagree about where the answer lives, so this is
74
+ * computed once and reused by both the direct-SDK and relay send paths.
75
+ *
76
+ * iOS reads the payload: a `sound` object with `critical: true` plus
77
+ * `interruptionLevel: "critical"` is what makes APNs ignore the ringer switch
78
+ * and Focus, and it is refused unless the app carries Apple's critical-alert
79
+ * entitlement.
80
+ *
81
+ * Android ignores all of that and reads the CHANNEL. Sound, importance and Do
82
+ * Not Disturb bypass are baked into the channel when the app creates it and
83
+ * cannot be raised by a payload, so the only lever the server has is which
84
+ * channel id it names.
85
+ */
86
+ export type ExpoPushSound =
87
+ | string
88
+ | null
89
+ | {
90
+ critical?: boolean;
91
+ name?: string | null;
92
+ volume?: number;
93
+ };
94
+
95
+ export type ExpoInterruptionLevel =
96
+ | "active"
97
+ | "critical"
98
+ | "passive"
99
+ | "time-sensitive";
100
+
101
+ export interface ExpoDeliveryOptions {
102
+ channelId: string;
103
+ sound: ExpoPushSound;
104
+ priority: "high";
105
+ interruptionLevel?: ExpoInterruptionLevel;
106
+ }
107
+
70
108
  export default class PushNotificationService {
71
109
  public static isWebPushInitialized = false;
72
110
  private static expoClient: Expo = new Expo(
@@ -408,6 +446,57 @@ export default class PushNotificationService {
408
446
  }
409
447
  }
410
448
 
449
+ /*
450
+ * Volume is pinned rather than exposed as a setting. A critical alert exists
451
+ * to wake somebody, and a responder who has already opted this device in and
452
+ * granted the OS permission has not asked to be woken quietly.
453
+ */
454
+ public static readonly CRITICAL_ALERT_VOLUME: number = 1;
455
+
456
+ public static getExpoDeliveryOptions(
457
+ message: PushNotificationMessage,
458
+ deviceType: PushDeviceType,
459
+ ): ExpoDeliveryOptions {
460
+ const isAndroid: boolean = deviceType === PushDeviceType.Android;
461
+ const isCritical: boolean = Boolean(message.isCriticalAlert);
462
+
463
+ /*
464
+ * iOS has no channels, so "default" here is the payload's own sound rather
465
+ * than a channel id. Android without the critical flag stays on
466
+ * oncall_high, which is what every push has used until now.
467
+ */
468
+ const channelId: string = isAndroid
469
+ ? isCritical
470
+ ? AndroidNotificationChannel.Critical
471
+ : AndroidNotificationChannel.High
472
+ : "default";
473
+
474
+ if (!isCritical) {
475
+ return {
476
+ channelId: channelId,
477
+ sound: "default",
478
+ priority: "high",
479
+ };
480
+ }
481
+
482
+ return {
483
+ channelId: channelId,
484
+ /*
485
+ * Sent to Android too, and harmlessly ignored there. Expo forwards it to
486
+ * APNs where it is the whole mechanism, and to FCM where the channel has
487
+ * already decided the sound; keeping one shape avoids a per-platform
488
+ * branch that could silently drop the iOS half.
489
+ */
490
+ sound: {
491
+ critical: true,
492
+ name: "default",
493
+ volume: PushNotificationService.CRITICAL_ALERT_VOLUME,
494
+ },
495
+ priority: "high",
496
+ interruptionLevel: "critical",
497
+ };
498
+ }
499
+
411
500
  private static async sendExpoPushNotification(
412
501
  expoPushToken: string,
413
502
  message: PushNotificationMessage,
@@ -430,8 +519,10 @@ export default class PushNotificationService {
430
519
  dataPayload["url"] = message.url || message.clickAction || "";
431
520
  }
432
521
 
433
- const channelId: string =
434
- deviceType === PushDeviceType.Android ? "oncall_high" : "default";
522
+ const delivery: ExpoDeliveryOptions = this.getExpoDeliveryOptions(
523
+ message,
524
+ deviceType,
525
+ );
435
526
 
436
527
  // If EXPO_ACCESS_TOKEN is not set, relay through the push notification gateway
437
528
  if (!ExpoAccessToken) {
@@ -439,7 +530,7 @@ export default class PushNotificationService {
439
530
  expoPushToken,
440
531
  message,
441
532
  dataPayload,
442
- channelId,
533
+ delivery,
443
534
  deviceType,
444
535
  );
445
536
  return;
@@ -452,9 +543,12 @@ export default class PushNotificationService {
452
543
  title: message.title,
453
544
  body: message.body,
454
545
  data: dataPayload,
455
- sound: "default",
456
- priority: "high",
457
- channelId: channelId,
546
+ sound: delivery.sound,
547
+ priority: delivery.priority,
548
+ channelId: delivery.channelId,
549
+ ...(delivery.interruptionLevel
550
+ ? { interruptionLevel: delivery.interruptionLevel }
551
+ : {}),
458
552
  };
459
553
 
460
554
  const tickets: ExpoPushTicket[] =
@@ -500,7 +594,7 @@ export default class PushNotificationService {
500
594
  expoPushToken: string,
501
595
  message: PushNotificationMessage,
502
596
  dataPayload: { [key: string]: string },
503
- channelId: string,
597
+ delivery: ExpoDeliveryOptions,
504
598
  deviceType: PushDeviceType,
505
599
  ): Promise<void> {
506
600
  logger.info(
@@ -516,9 +610,19 @@ export default class PushNotificationService {
516
610
  title: message.title || "",
517
611
  body: message.body || "",
518
612
  data: dataPayload,
519
- sound: "default",
520
- priority: "high",
521
- channelId: channelId,
613
+ /*
614
+ * The relay re-sends exactly what it is given, so a critical page
615
+ * that loses its sound object here arrives on the responder's
616
+ * phone as an ordinary silent notification. That is the failure
617
+ * this feature exists to prevent, so the whole delivery shape
618
+ * crosses the wire rather than the channel id alone.
619
+ */
620
+ sound: delivery.sound,
621
+ priority: delivery.priority,
622
+ channelId: delivery.channelId,
623
+ ...(delivery.interruptionLevel
624
+ ? { interruptionLevel: delivery.interruptionLevel }
625
+ : {}),
522
626
  },
523
627
  });
524
628
 
@@ -552,9 +656,10 @@ export default class PushNotificationService {
552
656
  title?: string;
553
657
  body?: string;
554
658
  data?: { [key: string]: string };
555
- sound?: string;
659
+ sound?: ExpoPushSound;
556
660
  priority?: string;
557
661
  channelId?: string;
662
+ interruptionLevel?: ExpoInterruptionLevel;
558
663
  }): Promise<void> {
559
664
  if (!ExpoAccessToken) {
560
665
  throw new Error(
@@ -562,14 +667,24 @@ export default class PushNotificationService {
562
667
  );
563
668
  }
564
669
 
670
+ /*
671
+ * `sound: null` is a caller asking for a silent notification and has to
672
+ * survive, so the fallback tests for undefined rather than falsiness.
673
+ */
674
+ const sound: ExpoPushSound =
675
+ data.sound === undefined ? "default" : data.sound;
676
+
565
677
  const expoPushMessage: ExpoPushMessage = {
566
678
  to: data.to,
567
679
  title: data.title || "",
568
680
  body: data.body || "",
569
681
  data: data.data || {},
570
- sound: (data.sound as "default" | null) || "default",
682
+ sound: sound,
571
683
  priority: (data.priority as "default" | "normal" | "high") || "high",
572
684
  channelId: data.channelId || "default",
685
+ ...(data.interruptionLevel
686
+ ? { interruptionLevel: data.interruptionLevel }
687
+ : {}),
573
688
  };
574
689
 
575
690
  const tickets: ExpoPushTicket[] =
@@ -14,6 +14,9 @@ import SortOrder from "../../Types/BaseDatabase/SortOrder";
14
14
  import InBetween from "../../Types/BaseDatabase/InBetween";
15
15
  import Includes from "../../Types/BaseDatabase/Includes";
16
16
  import ObjectID from "../../Types/ObjectID";
17
+ import FindBy from "../Types/AnalyticsDatabase/FindBy";
18
+ import { OnFind } from "../Types/AnalyticsDatabase/Hooks";
19
+ import ResourceEntityFilter from "../Utils/Telemetry/ResourceEntityFilter";
17
20
 
18
21
  /**
19
22
  * Columns the proj_hist_by_minute projection can answer with. If a count
@@ -35,6 +38,24 @@ export class SpanService extends AnalyticsDatabaseService<Span> {
35
38
  super({ modelType: Span, database: clickhouseDatabase });
36
39
  }
37
40
 
41
+ /*
42
+ * Resolve the traces explorer's resource-facet selections (a Kubernetes
43
+ * cluster, a host, ...) before the query is compiled. They arrive as
44
+ * Postgres ids under `resourceFilters`; matching them needs the
45
+ * resource's entity key, which only Postgres can supply. See
46
+ * ResourceEntityFilter.
47
+ */
48
+ protected override async onBeforeFind(
49
+ findBy: FindBy<Span>,
50
+ ): Promise<OnFind<Span>> {
51
+ await ResourceEntityFilter.rewriteAnalyticsQuery({
52
+ query: findBy.query as unknown as Record<string, unknown>,
53
+ projectId: findBy.props?.tenantId,
54
+ });
55
+
56
+ return { findBy, carryForward: null };
57
+ }
58
+
38
59
  /**
39
60
  * Normalize a JSON-deserialized date value to a Date instance. When a query
40
61
  * crosses the API boundary, InBetween's startValue/endValue come back as ISO
@@ -10,6 +10,7 @@ import UpdateBy from "../Types/Database/UpdateBy";
10
10
  import Errors from "../Utils/Errors";
11
11
  import logger, { LogAttributes } from "../Utils/Logger";
12
12
  import ProductAnalytics from "../Utils/ProductAnalytics";
13
+ import UserRegistrationToken from "../Utils/UserRegistrationToken";
13
14
  import AccessTokenService from "./AccessTokenService";
14
15
  import BillingService from "./BillingService";
15
16
  import DatabaseService from "./DatabaseService";
@@ -166,8 +167,23 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
166
167
  ? (createBy.miscDataProps["name"] as string).trim()
167
168
  : undefined;
168
169
 
169
- let user: User | null = await UserService.findByEmail(email, {
170
- isRoot: true,
170
+ /*
171
+ * `password` comes back too, because whether this person has finished
172
+ * registering decides both which link the invitation carries and whether
173
+ * that link needs a registration token. UserService.findByEmail selects
174
+ * only the id, so it cannot answer that.
175
+ */
176
+ let user: User | null = await UserService.findOneBy({
177
+ query: {
178
+ email: email,
179
+ },
180
+ select: {
181
+ _id: true,
182
+ password: true,
183
+ },
184
+ props: {
185
+ isRoot: true,
186
+ },
171
187
  });
172
188
 
173
189
  let isNewUser: boolean = false;
@@ -228,6 +244,39 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
228
244
  const host: Hostname = await DatabaseConfig.getHost();
229
245
  const httpProtocol: Protocol = await DatabaseConfig.getHttpProtocol();
230
246
 
247
+ /*
248
+ * "Still has to register", not "we just created the row". Someone
249
+ * invited to a second project before they ever signed up already has a
250
+ * user row and still has no password, and used to be sent the sign-in
251
+ * link — which they could not use, having no password to sign in with.
252
+ */
253
+ const needsRegistration: boolean = isNewUser || !user.password;
254
+
255
+ /*
256
+ * The token is what lets the recipient claim this account, so it exists
257
+ * only on the link inside this email and only for someone who has not
258
+ * registered yet. An already-registered invitee gets the plain link;
259
+ * they sign in instead, and minting a claim token for an account that
260
+ * cannot be claimed would just be a spare key lying around.
261
+ */
262
+ const registerLink: string = needsRegistration
263
+ ? (
264
+ await UserRegistrationToken.generateRegistrationLink({
265
+ userId: user.id!,
266
+ email: email,
267
+ })
268
+ ).toString()
269
+ : URL.fromString(
270
+ new URL(
271
+ httpProtocol,
272
+ host,
273
+ new Route(AccountsRoute.toString()),
274
+ ).toString(),
275
+ )
276
+ .addRoute("/register")
277
+ .addQueryParam("email", email.toString(), true)
278
+ .toString();
279
+
231
280
  MailService.sendMail(
232
281
  {
233
282
  toEmail: email,
@@ -240,17 +289,8 @@ export class TeamMemberService extends DatabaseService<TeamMember> {
240
289
  new Route(AccountsRoute.toString()),
241
290
  ).toString(),
242
291
  ).toString(),
243
- registerLink: URL.fromString(
244
- new URL(
245
- httpProtocol,
246
- host,
247
- new Route(AccountsRoute.toString()),
248
- ).toString(),
249
- )
250
- .addRoute("/register")
251
- .addQueryParam("email", email.toString(), true)
252
- .toString(),
253
- isNewUser: isNewUser.toString(),
292
+ registerLink: registerLink,
293
+ isNewUser: needsRegistration.toString(),
254
294
  /*
255
295
  * An auto-accepted member has nothing left to accept, so the
256
296
  * template drops the "sign in to accept your invitation" framing
@@ -11,6 +11,10 @@ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
11
11
  import { DbJSONResponse, Results } from "./AnalyticsDatabaseService";
12
12
  import logger from "../Utils/Logger";
13
13
  import ServiceType from "../../Types/Telemetry/ServiceType";
14
+ import {
15
+ appendResourceScopeFilters,
16
+ ResourceEntityScope,
17
+ } from "../Utils/Telemetry/ResourceEntityFilter";
14
18
  import ResourceFacetResolver, {
15
19
  ResolvedFacetValue,
16
20
  ResourceFacetSpec,
@@ -33,6 +37,15 @@ export type TraceAttributeFilters = Record<string, TraceAttributeFilterValue>;
33
37
  export interface TraceFilters {
34
38
  serviceIds?: Array<ObjectID> | undefined;
35
39
  entityKeys?: Array<string> | undefined;
40
+ /*
41
+ * Resource-facet selections (Kubernetes cluster / host / docker host /
42
+ * podman host) already resolved to their entity keys. One scope per
43
+ * facet: the branches inside a scope OR (a span proves membership either
44
+ * by being primary-keyed on the resource or by carrying its entity key),
45
+ * and the scopes AND with each other so two facets intersect. See
46
+ * ResourceEntityFilter.
47
+ */
48
+ resourceScopes?: Array<ResourceEntityScope> | undefined;
36
49
  statusCodes?: Array<number> | undefined;
37
50
  spanKinds?: Array<string> | undefined;
38
51
  spanNames?: Array<string> | undefined;
@@ -1008,6 +1021,8 @@ export class TraceAggregationService {
1008
1021
  );
1009
1022
  }
1010
1023
 
1024
+ appendResourceScopeFilters(statement, request.resourceScopes);
1025
+
1011
1026
  if (request.statusCodes && request.statusCodes.length > 0) {
1012
1027
  statement.append(
1013
1028
  SQL` AND statusCode IN (${{
@@ -16,7 +16,8 @@ import LIMIT_MAX from "../../Types/Database/LimitMax";
16
16
  import TwilioConfig from "../../Types/CallAndSMS/TwilioConfig";
17
17
  import BadDataException from "../../Types/Exception/BadDataException";
18
18
  import ObjectID from "../../Types/ObjectID";
19
- import Text from "../../Types/Text";
19
+ import TooManyRequestsException from "../../Types/Exception/TooManyRequestsException";
20
+ import ChannelVerification from "../Utils/ChannelVerification";
20
21
  import Project from "../../Models/DatabaseModels/Project";
21
22
  import Model from "../../Models/DatabaseModels/UserCall";
22
23
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
@@ -144,7 +145,8 @@ export class Service extends DatabaseService<Model> {
144
145
  createdItem: Model,
145
146
  ): Promise<Model> {
146
147
  if (!createdItem.isVerified) {
147
- this.sendVerificationCode(createdItem);
148
+ // issue and send the first verification code
149
+ await this.issueAndSendVerificationCode(createdItem);
148
150
  }
149
151
  return createdItem;
150
152
  }
@@ -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,57 @@ 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 {
269
+ // add space to make it more clear and slow down the message
270
+ const spokenCode: string = code.split("").join(" ");
271
+
235
272
  const callRequest: CallRequest = {
236
273
  to: item.phone!,
237
274
  data: [
@@ -239,19 +276,13 @@ export class Service extends DatabaseService<Model> {
239
276
  sayMessage: "This call is from One Uptime.",
240
277
  },
241
278
  {
242
- sayMessage:
243
- "Your verification code is " +
244
- item.verificationCode?.split("").join(" "), // add space to make it more clear and slow down the message
279
+ sayMessage: "Your verification code is " + spokenCode,
245
280
  },
246
281
  {
247
- sayMessage:
248
- "Your verification code is " +
249
- item.verificationCode?.split("").join(" "), // add space to make it more clear and slow down the message
282
+ sayMessage: "Your verification code is " + spokenCode,
250
283
  },
251
284
  {
252
- sayMessage:
253
- "Your verification code is " +
254
- item.verificationCode?.split("").join(" "), // add space to make it more clear and slow down the message
285
+ sayMessage: "Your verification code is " + spokenCode,
255
286
  },
256
287
  {
257
288
  sayMessage: "Thank you for using One Uptime. Goodbye.",
@@ -12,7 +12,8 @@ import LIMIT_MAX from "../../Types/Database/LimitMax";
12
12
  import EmailTemplateType from "../../Types/Email/EmailTemplateType";
13
13
  import BadDataException from "../../Types/Exception/BadDataException";
14
14
  import ObjectID from "../../Types/ObjectID";
15
- import Text from "../../Types/Text";
15
+ import TooManyRequestsException from "../../Types/Exception/TooManyRequestsException";
16
+ import ChannelVerification from "../Utils/ChannelVerification";
16
17
  import Model from "../../Models/DatabaseModels/UserEmail";
17
18
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
18
19
 
@@ -100,8 +101,33 @@ export class Service extends DatabaseService<Model> {
100
101
  createdItem: Model,
101
102
  ): Promise<Model> {
102
103
  if (!createdItem.isVerified) {
103
- // send verification code
104
- this.sendVerificationCode(createdItem);
104
+ // issue and send the first verification code
105
+ const plainCode: string =
106
+ await this.issueAndSendVerificationCode(createdItem);
107
+
108
+ /*
109
+ * TEST-ONLY seam, OFF unless explicitly switched on.
110
+ *
111
+ * The plaintext code is otherwise only ever emailed - never returned by
112
+ * the API - which is deliberate: returning it would let a caller add
113
+ * anybody's address and confirm it instantly, the exact takeover the
114
+ * hashing/expiry/attempt controls exist to stop (see ChannelVerification
115
+ * and VerificationCode). The end-to-end stack has no mailbox to read the
116
+ * emailed code from, so this narrow hatch hands the code back on the
117
+ * create response for it to confirm the address the way a user would.
118
+ *
119
+ * It is gated on an environment variable that is unset in every shipped
120
+ * config and set true ONLY in the CI e2e job (docker-compose passes it
121
+ * through, .github/workflows/test-release.yaml sets it for the SaaS run).
122
+ * In production the flag is absent, this branch never runs, and the code
123
+ * never leaves the mail path.
124
+ */
125
+ if (
126
+ process.env["EXPOSE_VERIFICATION_CODE_IN_API_RESPONSE_FOR_E2E"] ===
127
+ "true"
128
+ ) {
129
+ createdItem.verificationCode = plainCode;
130
+ }
105
131
  }
106
132
 
107
133
  return createdItem;
@@ -116,9 +142,10 @@ export class Service extends DatabaseService<Model> {
116
142
  },
117
143
  select: {
118
144
  email: true,
119
- verificationCode: true,
120
145
  isVerified: true,
121
146
  projectId: true,
147
+ userId: true,
148
+ verificationCodeSentAt: true,
122
149
  },
123
150
  });
124
151
 
@@ -132,29 +159,68 @@ export class Service extends DatabaseService<Model> {
132
159
  throw new BadDataException("Email already verified");
133
160
  }
134
161
 
135
- // generate new verification code
136
- item.verificationCode = Text.generateRandomNumber(6);
162
+ /*
163
+ * Resend cooldown.
164
+ *
165
+ * Without it, spending the attempt budget on a code and asking for
166
+ * another one is free, which turns the attempt limit into a speed bump
167
+ * rather than a wall — and the resend control doubles as a way to send
168
+ * somebody unsolicited messages as fast as the network allows, at the
169
+ * project's expense.
170
+ */
171
+ const retryAfterSeconds: number =
172
+ ChannelVerification.getResendRetryAfterSeconds({
173
+ lastSentAt: item.verificationCodeSentAt,
174
+ });
137
175
 
138
- await this.updateOneById({
139
- id: item.id!,
140
- props: {
141
- isRoot: true,
142
- },
143
- data: {
144
- verificationCode: item.verificationCode,
145
- },
176
+ if (retryAfterSeconds > 0) {
177
+ throw new TooManyRequestsException(
178
+ `Please wait ${retryAfterSeconds} seconds before requesting another verification code.`,
179
+ );
180
+ }
181
+
182
+ await this.issueAndSendVerificationCode(item);
183
+ }
184
+
185
+ /*
186
+ * Mint a fresh code for this row, store only its digest, and send the
187
+ * plaintext to the channel.
188
+ *
189
+ * The plaintext exists in memory for exactly as long as it takes to hand it
190
+ * to the notification service and is never written anywhere. Everything
191
+ * about why — expiry, the attempt counter, rotation, the resend cooldown —
192
+ * is in Common/Server/Utils/ChannelVerification.ts.
193
+ *
194
+ * This does NOT check whether a send is allowed. Callers decide that:
195
+ * onCreateSuccess because a brand new row has never been sent to, and
196
+ * resendVerificationCode after the cooldown and the channel's own
197
+ * preconditions have passed.
198
+ */
199
+ @CaptureSpan()
200
+ public async issueAndSendVerificationCode(item: Model): Promise<string> {
201
+ const plainCode: string = await ChannelVerification.issueCodeOnItem({
202
+ service: this,
203
+ itemId: item.id!,
146
204
  });
147
205
 
148
- this.sendVerificationCode(item);
206
+ this.sendVerificationCode(item, plainCode);
207
+
208
+ /*
209
+ * The plaintext exists here for exactly as long as it takes to hand it to
210
+ * the mailer, and is returned so a caller that has a legitimate reason to
211
+ * see it can - see onCreateSuccess for the one place that does, and the
212
+ * hard gate around it.
213
+ */
214
+ return plainCode;
149
215
  }
150
216
 
151
- public sendVerificationCode(item: Model): void {
217
+ public sendVerificationCode(item: Model, code: string): void {
152
218
  MailService.sendMail(
153
219
  {
154
220
  toEmail: item.email!,
155
221
  templateType: EmailTemplateType.VerificationCode,
156
222
  vars: {
157
- code: item.verificationCode!,
223
+ code: code,
158
224
  subject: "Verify this email address",
159
225
  },
160
226
  subject: "Verify this email address",