@oneuptime/common 14.0.13 → 14.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 (1045) hide show
  1. package/Models/DatabaseModels/AlertGroupingRule.ts +10 -6
  2. package/Models/DatabaseModels/File.ts +41 -2
  3. package/Models/DatabaseModels/Form.ts +126 -0
  4. package/Models/DatabaseModels/IncidentGroupingRule.ts +10 -6
  5. package/Models/DatabaseModels/LogDropFilter.ts +1 -0
  6. package/Models/DatabaseModels/LogPipeline.ts +1 -0
  7. package/Models/DatabaseModels/LogScrubRule.ts +14 -8
  8. package/Models/DatabaseModels/MetricRecordingRule.ts +2 -1
  9. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.ts +4 -2
  10. package/Models/DatabaseModels/OnCallDutyPolicyUserOverride.ts +22 -9
  11. package/Models/DatabaseModels/ProjectCallSMSConfig.ts +6 -1
  12. package/Models/DatabaseModels/StatusPage.ts +8 -4
  13. package/Models/DatabaseModels/TraceDropFilter.ts +1 -0
  14. package/Models/DatabaseModels/TracePipeline.ts +1 -0
  15. package/Models/DatabaseModels/TraceRecordingRule.ts +2 -1
  16. package/Models/DatabaseModels/TraceScrubRule.ts +14 -8
  17. package/Models/DatabaseModels/UserOnCallLog.ts +4 -2
  18. package/Server/API/CustomDomainRoutes.ts +251 -0
  19. package/Server/API/DashboardAPI.ts +33 -4
  20. package/Server/API/DashboardDomainAPI.ts +63 -93
  21. package/Server/API/StatusPageAPI.ts +92 -0
  22. package/Server/API/StatusPageDomainAPI.ts +59 -96
  23. package/Server/Infrastructure/GlobalCache.ts +84 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1797700000000-AddFormBranding.ts +47 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  26. package/Server/Services/AlertGroupingEngineService.ts +48 -70
  27. package/Server/Services/AlertGroupingRuleService.ts +38 -0
  28. package/Server/Services/CephClusterService.ts +25 -0
  29. package/Server/Services/CloudResourceService.ts +42 -0
  30. package/Server/Services/DashboardDomainService.ts +640 -214
  31. package/Server/Services/DashboardService.ts +30 -8
  32. package/Server/Services/DatabaseService.ts +143 -12
  33. package/Server/Services/DockerHostService.ts +60 -0
  34. package/Server/Services/DockerSwarmClusterService.ts +25 -0
  35. package/Server/Services/FileService.ts +60 -0
  36. package/Server/Services/FormService.ts +212 -2
  37. package/Server/Services/GlobalOidcService.ts +10 -0
  38. package/Server/Services/GlobalSsoService.ts +10 -0
  39. package/Server/Services/HostService.ts +58 -0
  40. package/Server/Services/IncidentGroupingEngineService.ts +48 -70
  41. package/Server/Services/IncidentGroupingRuleService.ts +38 -0
  42. package/Server/Services/IoTFleetService.ts +26 -0
  43. package/Server/Services/KubernetesClusterService.ts +64 -0
  44. package/Server/Services/LabelService.ts +6 -17
  45. package/Server/Services/LogScrubRuleService.ts +50 -0
  46. package/Server/Services/OnCallDutyPolicyScheduleService.ts +264 -0
  47. package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +9 -1
  48. package/Server/Services/OnCallNotificationAlertingService.ts +24 -29
  49. package/Server/Services/OnCallSetupReminderService.ts +41 -40
  50. package/Server/Services/PodmanHostService.ts +60 -0
  51. package/Server/Services/ProfileAggregationService.ts +38 -0
  52. package/Server/Services/ProjectCallSMSConfigService.ts +76 -3
  53. package/Server/Services/ProjectOidcService.ts +20 -0
  54. package/Server/Services/ProjectSsoService.ts +20 -0
  55. package/Server/Services/ProxmoxClusterService.ts +25 -0
  56. package/Server/Services/RumApplicationService.ts +45 -0
  57. package/Server/Services/ScheduledMaintenanceService.ts +9 -23
  58. package/Server/Services/ServerlessFunctionService.ts +47 -0
  59. package/Server/Services/ServiceService.ts +33 -10
  60. package/Server/Services/StatusPageDomainService.ts +622 -213
  61. package/Server/Services/StatusPageOidcService.ts +20 -0
  62. package/Server/Services/StatusPageResourceService.ts +89 -34
  63. package/Server/Services/StatusPageService.ts +270 -54
  64. package/Server/Services/StatusPageSsoService.ts +20 -0
  65. package/Server/Services/TraceScrubRuleService.ts +50 -0
  66. package/Server/Services/UserIncomingCallNumberService.ts +28 -14
  67. package/Server/Services/VMwareVCenterService.ts +25 -0
  68. package/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.ts +3 -3
  69. package/Server/Utils/Greenlock/CertificateOrder.ts +482 -0
  70. package/Server/Utils/Greenlock/CertificateOrderBudget.ts +134 -0
  71. package/Server/Utils/Greenlock/CertificateOrderFailures.ts +288 -0
  72. package/Server/Utils/Greenlock/CertificateOrderLock.ts +163 -0
  73. package/Server/Utils/Greenlock/CertificateOrderOutcome.ts +29 -0
  74. package/Server/Utils/Greenlock/CertificateOwners.ts +72 -0
  75. package/Server/Utils/Greenlock/CertificateReissueOrder.ts +99 -0
  76. package/Server/Utils/Greenlock/CustomDomainOrders.ts +397 -0
  77. package/Server/Utils/Greenlock/Greenlock.ts +839 -203
  78. package/Server/Utils/Rules/GroupingRuleEpisodeOwners.ts +551 -0
  79. package/Server/Utils/Rules/OwnerRuleAssignment.ts +8 -1
  80. package/Server/Utils/ScrubRuleValidation.ts +248 -0
  81. package/Server/Utils/StatusPage/AffectedStatusPageResources.ts +138 -0
  82. package/Server/Utils/StatusPage/StatusPagesListingMonitorsBuilder.ts +294 -0
  83. package/Server/Utils/Telemetry/DiscoveredResourceCreate.ts +275 -0
  84. package/Server/Utils/Telemetry/DiscoveredResourceUpdate.ts +217 -0
  85. package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +8 -2
  86. package/Tests/App/Accounts/FormPage.test.tsx +238 -0
  87. package/Tests/App/Accounts/FormUtils.test.ts +108 -0
  88. package/Tests/App/AdminDashboard/AdminAddToProjectMembersTeam.test.tsx +1087 -0
  89. package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +140 -138
  90. package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +144 -145
  91. package/Tests/App/AdminDashboard/AdminSettingsFormsOnePage.test.tsx +907 -0
  92. package/Tests/App/AdminDashboard/AdminSettingsSwitches.test.tsx +906 -0
  93. package/Tests/App/AdminDashboard/AdminSmtpSettingsForm.test.tsx +823 -0
  94. package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +341 -368
  95. package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +199 -54
  96. package/Tests/App/AdminDashboard/ProjectScopedTeamsPicker.test.tsx +991 -0
  97. package/Tests/App/Dashboard/AIInvestigationSettingsLimits.test.tsx +147 -90
  98. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +224 -104
  99. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +302 -0
  100. package/Tests/App/Dashboard/AdminUserOnCallPages.test.tsx +408 -152
  101. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +55 -0
  102. package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +206 -115
  103. package/Tests/App/Dashboard/AffectedResourcesPickerFocusLeave.test.tsx +32 -0
  104. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +206 -71
  105. package/Tests/App/Dashboard/AlertEpisodeViewFields.test.tsx +45 -9
  106. package/Tests/App/Dashboard/AnnouncementCreateForm.test.tsx +1208 -0
  107. package/Tests/App/Dashboard/AnnouncementEditAndTemplateForms.test.tsx +693 -0
  108. package/Tests/App/Dashboard/AnnouncementFormsStructure.test.ts +546 -0
  109. package/Tests/App/Dashboard/AnnouncementStatusPageSuggestions.test.tsx +425 -0
  110. package/Tests/App/Dashboard/AnnouncementsTableCreateLinks.test.tsx +267 -0
  111. package/Tests/App/Dashboard/ApiKeyCreateForm.test.ts +68 -51
  112. package/Tests/App/Dashboard/ApiKeyViewPermissions.test.tsx +11 -9
  113. package/Tests/App/Dashboard/ApiKeysCreateAccess.test.tsx +24 -16
  114. package/Tests/App/Dashboard/BulkChangeStateModalOnePage.test.tsx +333 -0
  115. package/Tests/App/Dashboard/CardDescriptionsSayWhatFor.test.tsx +307 -0
  116. package/Tests/App/Dashboard/ChangeAlertStateAIHeader.test.tsx +18 -4
  117. package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +7 -2
  118. package/Tests/App/Dashboard/ColorFieldsPrefilledPages.test.tsx +453 -0
  119. package/Tests/App/Dashboard/CreateFromRecordBreadcrumbs.test.ts +272 -0
  120. package/Tests/App/Dashboard/CreateFromRecordLinks.test.tsx +495 -0
  121. package/Tests/App/Dashboard/CreateFromRecordPages.test.tsx +1026 -0
  122. package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +65 -23
  123. package/Tests/App/Dashboard/CriteriaName.test.ts +5 -1
  124. package/Tests/App/Dashboard/CustomDomainCreateFlow.test.tsx +516 -0
  125. package/Tests/App/Dashboard/CustomDomainDnsSetupModal.test.tsx +547 -0
  126. package/Tests/App/Dashboard/CustomDomainsPages.test.tsx +1077 -0
  127. package/Tests/App/Dashboard/CustomFieldSimpleCreate.test.tsx +2 -2
  128. package/Tests/App/Dashboard/CustomFieldSimpleCreateRender.test.tsx +12 -6
  129. package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +1 -1
  130. package/Tests/App/Dashboard/CustomSmtpConfigForm.test.tsx +969 -0
  131. package/Tests/App/Dashboard/DashboardBlankCanvasAddWidget.test.tsx +425 -0
  132. package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +400 -0
  133. package/Tests/App/Dashboard/DashboardComponentsMRTranslation.test.tsx +4 -3
  134. package/Tests/App/Dashboard/DashboardCreateForm.test.ts +375 -0
  135. package/Tests/App/Dashboard/DashboardCreateFromTemplate.test.tsx +727 -0
  136. package/Tests/App/Dashboard/DashboardEmptyCanvasAddWidget.test.tsx +86 -0
  137. package/Tests/App/Dashboard/DashboardPhoneProductsMenu.test.tsx +99 -9
  138. package/Tests/App/Dashboard/DashboardSharingCard.test.tsx +1226 -0
  139. package/Tests/App/Dashboard/DashboardSharingEntryPoints.test.tsx +383 -0
  140. package/Tests/App/Dashboard/DashboardSharingPage.test.tsx +478 -0
  141. package/Tests/App/Dashboard/DeclareFormsAdvancedRender.test.tsx +90 -34
  142. package/Tests/App/Dashboard/DeclareIncidentMonitorsApart.test.tsx +1028 -0
  143. package/Tests/App/Dashboard/DefaultSsoTeams.test.tsx +215 -0
  144. package/Tests/App/Dashboard/DisabledWarningArchived.test.tsx +3 -3
  145. package/Tests/App/Dashboard/DisabledWarningRobustness.test.tsx +15 -12
  146. package/Tests/App/Dashboard/DiscoveredResourceCreateForms.test.tsx +936 -0
  147. package/Tests/App/Dashboard/EmbeddedMetricCardGroup.test.tsx +720 -0
  148. package/Tests/App/Dashboard/EpisodeMemberRoleAssignmentsFormField.test.tsx +331 -0
  149. package/Tests/App/Dashboard/EpisodePostmortemPage.test.tsx +327 -0
  150. package/Tests/App/Dashboard/EscalationRuleForm.test.ts +2 -2
  151. package/Tests/App/Dashboard/EscalationRuleFormGuard.test.ts +6 -2
  152. package/Tests/App/Dashboard/EscalationRuleOneStep.test.tsx +8 -4
  153. package/Tests/App/Dashboard/EventMeasurements.test.ts +1175 -0
  154. package/Tests/App/Dashboard/EventMeasurementsCard.test.tsx +993 -0
  155. package/Tests/App/Dashboard/EventNoteComposerDialog.test.tsx +939 -0
  156. package/Tests/App/Dashboard/EventNotes.test.tsx +34 -1
  157. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +186 -1
  158. package/Tests/App/Dashboard/EventSettingsSwitchPages.test.tsx +625 -0
  159. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +6 -2
  160. package/Tests/App/Dashboard/FeedNoteComposerDialog.test.tsx +1327 -0
  161. package/Tests/App/Dashboard/FeedNoteDialogHelpers.ts +109 -0
  162. package/Tests/App/Dashboard/FilterChipClearButton.test.tsx +356 -0
  163. package/Tests/App/Dashboard/FormBrandingSection.test.tsx +504 -0
  164. package/Tests/App/Dashboard/FormBrandingValues.test.ts +255 -0
  165. package/Tests/App/Dashboard/FormBuilderParts.test.tsx +38 -1
  166. package/Tests/App/Dashboard/FormBuilderUi.test.tsx +176 -2
  167. package/Tests/App/Dashboard/FormMappingCard.test.tsx +33 -13
  168. package/Tests/App/Dashboard/FormsMovedPagesAndSubmissions.test.tsx +1 -1
  169. package/Tests/App/Dashboard/GeneratedKeyForms.test.tsx +30 -7
  170. package/Tests/App/Dashboard/GlobalProbesOnNewMonitorsCard.test.tsx +258 -0
  171. package/Tests/App/Dashboard/GroupingRuleFormFlow.test.tsx +653 -37
  172. package/Tests/App/Dashboard/GroupingRulePages.test.tsx +218 -9
  173. package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +52 -4
  174. package/Tests/App/Dashboard/IncidentEpisodeFeedPublicNoteNotifyDefault.test.tsx +230 -338
  175. package/Tests/App/Dashboard/IncidentEpisodeViewFields.test.tsx +45 -9
  176. package/Tests/App/Dashboard/IncidentFeedPublicNoteNotifyDefault.test.tsx +227 -295
  177. package/Tests/App/Dashboard/IncidentLinkedAlertsSettingsPage.test.tsx +157 -181
  178. package/Tests/App/Dashboard/IncidentPostmortemPage.test.tsx +775 -0
  179. package/Tests/App/Dashboard/IncidentRoleFormField.test.tsx +379 -15
  180. package/Tests/App/Dashboard/IncidentRolesSettingsPage.test.tsx +148 -32
  181. package/Tests/App/Dashboard/IncidentTemplateInitialState.test.tsx +430 -0
  182. package/Tests/App/Dashboard/IncidentTemplateMonitorsApart.test.tsx +492 -0
  183. package/Tests/App/Dashboard/IncomingCallEscalationOneStep.test.tsx +830 -0
  184. package/Tests/App/Dashboard/IncomingCallEscalationRuleForm.test.ts +510 -0
  185. package/Tests/App/Dashboard/IncomingCallEscalationRuleFormGuard.test.ts +378 -0
  186. package/Tests/App/Dashboard/IngestionKeyForm.test.ts +664 -0
  187. package/Tests/App/Dashboard/IngestionKeySelectorCreate.test.tsx +523 -0
  188. package/Tests/App/Dashboard/InventoryTypeAndStatusFacets.test.tsx +130 -9
  189. package/Tests/App/Dashboard/IpAllowlistCopy.test.ts +122 -0
  190. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +19 -3
  191. package/Tests/App/Dashboard/KubernetesMetricsSetupEmptyState.test.tsx +275 -0
  192. package/Tests/App/Dashboard/KubernetesMetricsSetupHints.test.tsx +720 -0
  193. package/Tests/App/Dashboard/LabelsFormField.test.tsx +18 -13
  194. package/Tests/App/Dashboard/LegacyDefaultAssigneeNote.test.tsx +359 -0
  195. package/Tests/App/Dashboard/LogMonitorAttributeOperatorPreview.test.tsx +10 -10
  196. package/Tests/App/Dashboard/MarkdownTemplateDialogsWide.test.tsx +42 -20
  197. package/Tests/App/Dashboard/MeasurementForms.test.tsx +191 -5
  198. package/Tests/App/Dashboard/MeasurementPagesI18n.test.ts +2 -0
  199. package/Tests/App/Dashboard/MeasurementSetup.test.ts +5 -2
  200. package/Tests/App/Dashboard/MenuSpecificFoldedSections.test.tsx +38 -12
  201. package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +34 -11
  202. package/Tests/App/Dashboard/MetricAndRecordingRuleFormsRender.test.tsx +1206 -0
  203. package/Tests/App/Dashboard/MetricResultsState.test.ts +248 -0
  204. package/Tests/App/Dashboard/MetricViewResultsState.test.tsx +404 -0
  205. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +1 -1
  206. package/Tests/App/Dashboard/MonitorCriteriaAdvancedOptions.test.tsx +77 -27
  207. package/Tests/App/Dashboard/MonitorCriteriaAttributeFilter.test.tsx +5 -8
  208. package/Tests/App/Dashboard/MonitorCriteriaHeaderControls.test.tsx +228 -0
  209. package/Tests/App/Dashboard/MonitorCriteriaIncidentRoles.test.tsx +411 -0
  210. package/Tests/App/Dashboard/MonitorFeedRefresh.test.tsx +5 -1
  211. package/Tests/App/Dashboard/MonitorFormIncidentRoles.test.tsx +460 -0
  212. package/Tests/App/Dashboard/MonitorIntervalRedirect.test.tsx +299 -0
  213. package/Tests/App/Dashboard/MonitorOverviewHero.test.tsx +243 -2
  214. package/Tests/App/Dashboard/MonitorProbesAndIntervalPage.test.tsx +638 -0
  215. package/Tests/App/Dashboard/MonitorStepsDefaultStatusAdvanced.test.tsx +2 -2
  216. package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +2 -2
  217. package/Tests/App/Dashboard/MonitoringIntervalCard.test.tsx +493 -0
  218. package/Tests/App/Dashboard/MonitoringSwitch.test.tsx +597 -0
  219. package/Tests/App/Dashboard/MovedRunnerSettingsRedirects.test.tsx +4 -5
  220. package/Tests/App/Dashboard/NotificationChannelOffSwitchLists.test.tsx +636 -0
  221. package/Tests/App/Dashboard/OnCallPolicyCreateFormGuard.test.ts +8 -4
  222. package/Tests/App/Dashboard/OnCallPolicyFirstResponders.test.tsx +1 -1
  223. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +54 -0
  224. package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +43 -24
  225. package/Tests/App/Dashboard/OnCallRulesRedirects.test.tsx +530 -0
  226. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +158 -74
  227. package/Tests/App/Dashboard/OnCallRulesTabs.test.tsx +511 -0
  228. package/Tests/App/Dashboard/OnCallScheduleAddLayerDefaults.test.tsx +236 -0
  229. package/Tests/App/Dashboard/OnCallScheduleCreateFormGuard.test.ts +633 -0
  230. package/Tests/App/Dashboard/OnCallScheduleOverrideClarity.test.tsx +13 -2
  231. package/Tests/App/Dashboard/OnCallScheduleWhoTakesTurns.test.tsx +771 -0
  232. package/Tests/App/Dashboard/OnCallSharedCalendarFeedSettingsForm.test.tsx +357 -0
  233. package/Tests/App/Dashboard/OnCallShiftRemindersAndUpcomingShifts.test.tsx +16 -6
  234. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +112 -23
  235. package/Tests/App/Dashboard/PageSearchIndexCoversMenus.test.tsx +594 -0
  236. package/Tests/App/Dashboard/PageSearchIndexCoversRoutes.test.tsx +271 -0
  237. package/Tests/App/Dashboard/PageSearchRanking.test.tsx +373 -0
  238. package/Tests/App/Dashboard/PostmortemPageParts.test.tsx +548 -0
  239. package/Tests/App/Dashboard/ProbeAgreementCard.test.tsx +483 -0
  240. package/Tests/App/Dashboard/ProductOrientation.test.tsx +9 -2
  241. package/Tests/App/Dashboard/ProjectAISettingsPages.test.tsx +282 -404
  242. package/Tests/App/Dashboard/ProjectAiSettingsSwitchPages.test.tsx +1414 -0
  243. package/Tests/App/Dashboard/ProjectNotificationChannels.test.tsx +1191 -0
  244. package/Tests/App/Dashboard/ProjectSettingsSwitchCards.test.tsx +603 -0
  245. package/Tests/App/Dashboard/RemindersCard.test.tsx +477 -0
  246. package/Tests/App/Dashboard/ResourceDetailsCard.test.tsx +458 -0
  247. package/Tests/App/Dashboard/ResourceRuleForm.test.ts +525 -0
  248. package/Tests/App/Dashboard/ResourceRuleFormsRender.test.tsx +803 -0
  249. package/Tests/App/Dashboard/RoleAccess.test.ts +753 -0
  250. package/Tests/App/Dashboard/RoleCardSelectOptions.test.ts +13 -6
  251. package/Tests/App/Dashboard/RouteUtilPageRoute.test.ts +116 -0
  252. package/Tests/App/Dashboard/RowActionPlacementOverrides.test.tsx +1 -1
  253. package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +172 -219
  254. package/Tests/App/Dashboard/RunbookStepHeaderControls.test.tsx +269 -0
  255. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +45 -85
  256. package/Tests/App/Dashboard/RunnerSupersededByAiAgentNote.test.tsx +16 -23
  257. package/Tests/App/Dashboard/ScheduledMaintenanceAffectedResourcesEditForm.test.tsx +485 -0
  258. package/Tests/App/Dashboard/ScheduledMaintenanceChangeStateNotifyDefault.test.tsx +27 -2
  259. package/Tests/App/Dashboard/ScheduledMaintenanceCreateForm.test.tsx +65 -28
  260. package/Tests/App/Dashboard/ScheduledMaintenanceFeedPublicNoteNotifyDefault.test.tsx +208 -309
  261. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +36 -53
  262. package/Tests/App/Dashboard/ScheduledMaintenanceFormsStructure.test.ts +83 -14
  263. package/Tests/App/Dashboard/ScheduledMaintenanceMonitorsApart.test.tsx +1085 -0
  264. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +378 -25
  265. package/Tests/App/Dashboard/ScheduledMaintenanceStatusPageSuggestions.test.tsx +513 -0
  266. package/Tests/App/Dashboard/ScheduledMaintenanceTemplateForm.test.tsx +31 -9
  267. package/Tests/App/Dashboard/ScheduledMaintenanceTemplateMonitorsApart.test.tsx +760 -0
  268. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +11 -13
  269. package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +228 -69
  270. package/Tests/App/Dashboard/SelectedProjectSwitches.test.tsx +359 -0
  271. package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1 -1
  272. package/Tests/App/Dashboard/SessionReplayAllowedCard.test.tsx +297 -0
  273. package/Tests/App/Dashboard/SetupGuideCard.test.tsx +7 -1
  274. package/Tests/App/Dashboard/ShortFormsOnePage.test.tsx +591 -0
  275. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +253 -6
  276. package/Tests/App/Dashboard/SloOverviewData.test.tsx +99 -0
  277. package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +3 -1
  278. package/Tests/App/Dashboard/SloSettings.test.tsx +257 -4
  279. package/Tests/App/Dashboard/SsoPages.test.tsx +448 -52
  280. package/Tests/App/Dashboard/StateChangeDialogsFolded.test.tsx +695 -0
  281. package/Tests/App/Dashboard/StateChangeFormFields.test.ts +376 -0
  282. package/Tests/App/Dashboard/StatusPageAccessCard.test.tsx +1088 -0
  283. package/Tests/App/Dashboard/StatusPageAccessCopy.test.ts +450 -0
  284. package/Tests/App/Dashboard/StatusPageAccessMenu.test.tsx +137 -0
  285. package/Tests/App/Dashboard/StatusPageAccessPage.test.tsx +458 -0
  286. package/Tests/App/Dashboard/StatusPageAdvancedSettingsPage.test.tsx +30 -86
  287. package/Tests/App/Dashboard/StatusPageBrandingPage.test.tsx +28 -15
  288. package/Tests/App/Dashboard/StatusPageDisplaySettingsCard.test.tsx +949 -14
  289. package/Tests/App/Dashboard/StatusPagePrivateUsersNotice.test.tsx +233 -0
  290. package/Tests/App/Dashboard/StatusPageReportsCard.test.tsx +1001 -0
  291. package/Tests/App/Dashboard/StatusPageRequireSsoCard.test.tsx +247 -0
  292. package/Tests/App/Dashboard/StatusPageSubscriberSettingsPages.test.tsx +4 -17
  293. package/Tests/App/Dashboard/StatusPageSuggestions.test.tsx +930 -0
  294. package/Tests/App/Dashboard/StatusPageSwitchCardPages.test.tsx +335 -0
  295. package/Tests/App/Dashboard/TeamBlockPermissionsRedirect.test.tsx +332 -0
  296. package/Tests/App/Dashboard/TeamCreateForm.test.ts +206 -0
  297. package/Tests/App/Dashboard/TeamViewPermissions.test.tsx +713 -0
  298. package/Tests/App/Dashboard/TeamViewSideMenuBlockPermissions.test.tsx +113 -0
  299. package/Tests/App/Dashboard/TeamsCreateAccess.test.tsx +799 -0
  300. package/Tests/App/Dashboard/TelemetryDataRuleForms.test.ts +655 -0
  301. package/Tests/App/Dashboard/TelemetryDataRuleFormsRender.test.tsx +1014 -0
  302. package/Tests/App/Dashboard/TelemetryIngestionKeyEdit.test.tsx +6 -3
  303. package/Tests/App/Dashboard/TelemetryIngestionKeyForm.test.tsx +446 -446
  304. package/Tests/App/Dashboard/TelemetryMonitorFiltersFold.test.tsx +613 -0
  305. package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +37 -2
  306. package/Tests/App/Dashboard/TemplateFormsNoInternalDataWarning.test.tsx +3 -3
  307. package/Tests/App/Dashboard/TraceExplorer.test.tsx +338 -0
  308. package/Tests/App/Dashboard/TwilioConfigFirstDefault.test.tsx +786 -0
  309. package/Tests/App/Dashboard/UpcomingShiftGetCover.test.tsx +306 -0
  310. package/Tests/App/Dashboard/UseBulkShortenDeviceNames.test.tsx +36 -11
  311. package/Tests/App/Dashboard/UserOverrideForm.test.ts +505 -0
  312. package/Tests/App/Dashboard/UserOverrideFormGuard.test.ts +334 -0
  313. package/Tests/App/Dashboard/UserOverrideWhoIsAway.test.tsx +999 -0
  314. package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +33 -11
  315. package/Tests/App/Dashboard/UserSettingsSetupChecklistPage.test.tsx +49 -4
  316. package/Tests/App/Dashboard/UsersPageEmptyState.test.tsx +245 -0
  317. package/Tests/App/Dashboard/WorkflowVariableOAuthSettingsEditSteps.test.tsx +13 -6
  318. package/Tests/App/Dashboard/WorkspaceMenusConnected.test.tsx +0 -2
  319. package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +108 -86
  320. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +397 -0
  321. package/Tests/App/StatusPage/StatusPageResourceForm.test.tsx +931 -0
  322. package/Tests/App/StatusPage/StatusPageSubscribeOnePage.test.tsx +686 -0
  323. package/Tests/DialogActionRules.ts +16 -5
  324. package/Tests/Helpers/CardHeaderScan.ts +258 -0
  325. package/Tests/Helpers/FormStepsScan.ts +576 -11
  326. package/Tests/Helpers/MonitorGroupStatusPageRows.ts +237 -0
  327. package/Tests/Helpers/NestedControls.ts +184 -0
  328. package/Tests/Helpers/NestedControlsScan.ts +414 -0
  329. package/Tests/Helpers/SteppedFooterScan.ts +722 -0
  330. package/Tests/Models/DatabaseModels/FormModel.test.ts +31 -7
  331. package/Tests/Models/DatabaseModels/UserOverrideColumnDescriptions.test.ts +123 -0
  332. package/Tests/Models/TelemetryDataRuleColumnDefaults.test.ts +239 -0
  333. package/Tests/ResponsiveFlexLayout.test.ts +111 -0
  334. package/Tests/ResponsiveFlexLayout.ts +165 -0
  335. package/Tests/Server/API/DashboardDomainOrderSslAPI.test.ts +372 -0
  336. package/Tests/Server/API/DashboardDomainVerifyCnameAPI.test.ts +921 -0
  337. package/Tests/Server/API/DashboardSharingPublicRoutes.test.ts +559 -0
  338. package/Tests/Server/API/FormBrandingPublicRoutes.test.ts +680 -0
  339. package/Tests/Server/API/ProjectAPICreateWithTenantHeader.test.ts +300 -0
  340. package/Tests/Server/API/ProjectCreateTestHelpers.ts +211 -0
  341. package/Tests/Server/API/ProjectCreateWithTenantHeaderPostgres.test.ts +387 -0
  342. package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +29 -12
  343. package/Tests/Server/API/StatusPageDomainVerifyCnameAPI.test.ts +1090 -0
  344. package/Tests/Server/API/StatusPageMasterPageAccess.test.ts +254 -0
  345. package/Tests/Server/API/StatusPageReportScheduleWrites.test.ts +829 -0
  346. package/Tests/Server/API/StatusPageUptimeSettingsWrites.test.ts +417 -0
  347. package/Tests/Server/API/StatusPagesListingMonitorsAPI.test.ts +1029 -0
  348. package/Tests/Server/API/StatusPagesListingMonitorsRoute.test.ts +286 -0
  349. package/Tests/Server/Infrastructure/GlobalCache.test.ts +156 -0
  350. package/Tests/Server/Infrastructure/Postgres/MigrateIncidentFormsToFormsMigration.test.ts +52 -1
  351. package/Tests/Server/Services/CustomDomainCertificateLifecycle.test.ts +1559 -0
  352. package/Tests/Server/Services/CustomDomainCertificateReissue.test.ts +186 -16
  353. package/Tests/Server/Services/DashboardAccessChoice.test.ts +657 -0
  354. package/Tests/Server/Services/DashboardCreateFromTemplate.test.ts +200 -0
  355. package/Tests/Server/Services/DashboardDomainCertificateSweeps.test.ts +1142 -0
  356. package/Tests/Server/Services/DiscoveredResourceCreate.test.ts +864 -0
  357. package/Tests/Server/Services/DiscoveredResourceUpdate.test.ts +822 -0
  358. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +3 -4
  359. package/Tests/Server/Services/FileServiceProject.test.ts +345 -0
  360. package/Tests/Server/Services/FormBranding.test.ts +982 -0
  361. package/Tests/Server/Services/FormPublicForm.test.ts +15 -0
  362. package/Tests/Server/Services/GroupingRuleEpisodeOwners.test.ts +857 -0
  363. package/Tests/Server/Services/IncidentFormPostgres.test.ts +297 -1
  364. package/Tests/Server/Services/MachinePickedColors.test.ts +202 -0
  365. package/Tests/Server/Services/OidcProviderCreateDefaults.test.ts +252 -0
  366. package/Tests/Server/Services/OnCallDutyPolicyScheduleFirstLayer.test.ts +799 -0
  367. package/Tests/Server/Services/OnCallDutyPolicyScheduleFirstLayerPlans.test.ts +172 -0
  368. package/Tests/Server/Services/OnCallDutyPolicyUserOverrideWhoIsAway.test.ts +571 -0
  369. package/Tests/Server/Services/OnCallSetupReminder.test.ts +35 -13
  370. package/Tests/Server/Services/OnCallUndeliverablePageRulesLink.test.ts +217 -0
  371. package/Tests/Server/Services/ProfileAggregationService.test.ts +213 -4
  372. package/Tests/Server/Services/ProjectCallSMSConfigFirstDefault.test.ts +699 -0
  373. package/Tests/Server/Services/ProjectCallSMSConfigFirstDefaultBilling.test.ts +247 -0
  374. package/Tests/Server/Services/SamlProviderCreateDefaults.test.ts +255 -0
  375. package/Tests/Server/Services/ScheduledMaintenanceSubscriberMonitorGroups.test.ts +333 -0
  376. package/Tests/Server/Services/ScrubRuleSaveValidation.test.ts +947 -0
  377. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +17 -4
  378. package/Tests/Server/Services/StatusPageAccessChoice.test.ts +548 -0
  379. package/Tests/Server/Services/StatusPageDomainCertificateSweeps.test.ts +1238 -0
  380. package/Tests/Server/Services/TeamCreateAccessGrant.test.ts +607 -0
  381. package/Tests/Server/Services/TwilioConfigSendersGuard.test.ts +249 -0
  382. package/Tests/Server/Services/VerificationCodesUseProjectTwilioConfig.test.ts +264 -0
  383. package/Tests/Server/Types/Database/Permissions/FormBrandingColumns.test.ts +270 -0
  384. package/Tests/Server/Utils/Greenlock/CertificateCleanup.test.ts +526 -0
  385. package/Tests/Server/Utils/Greenlock/CertificateOrder.test.ts +1062 -0
  386. package/Tests/Server/Utils/Greenlock/CertificateOrderBudget.test.ts +243 -0
  387. package/Tests/Server/Utils/Greenlock/CertificateOrderFailures.test.ts +293 -0
  388. package/Tests/Server/Utils/Greenlock/CertificateOrderLock.test.ts +152 -0
  389. package/Tests/Server/Utils/Greenlock/CertificateOwnersGuard.test.ts +119 -0
  390. package/Tests/Server/Utils/Greenlock/CertificateRenewalOwnership.test.ts +1170 -0
  391. package/Tests/Server/Utils/Greenlock/CertificateRenewalSafety.test.ts +368 -0
  392. package/Tests/Server/Utils/Greenlock/CertificateRenewalSchedule.test.ts +188 -11
  393. package/Tests/Server/Utils/Greenlock/CustomDomainOrders.test.ts +723 -0
  394. package/Tests/Server/Utils/Greenlock/InMemoryRedis.ts +189 -0
  395. package/Tests/Server/Utils/Greenlock/NginxAcmeCertificatesToDisk.test.ts +242 -0
  396. package/Tests/Server/Utils/Greenlock/NginxCustomCertificatesToDisk.test.ts +305 -0
  397. package/Tests/Server/Utils/Greenlock/OrderCertGuards.test.ts +583 -0
  398. package/Tests/Server/Utils/Greenlock/OrderCertStorage.test.ts +203 -0
  399. package/Tests/Server/Utils/StatusPage/AffectedStatusPageResources.test.ts +700 -0
  400. package/Tests/Server/Utils/StatusPage/StatusPagesListingMonitorsBuilder.test.ts +744 -0
  401. package/Tests/Types/CustomDomain/CustomDomainCertificates.test.ts +106 -0
  402. package/Tests/Types/CustomDomain/CustomDomainVerification.test.ts +94 -0
  403. package/Tests/Types/Dashboard/DashboardAccess.test.ts +460 -0
  404. package/Tests/Types/Filter/FilterConditionUtil.test.ts +59 -0
  405. package/Tests/Types/Form/FormBranding.test.ts +760 -0
  406. package/Tests/Types/IncomingCall/IncomingCallRingTime.test.ts +80 -0
  407. package/Tests/Types/NotificationRule/OnCallRuleKind.test.ts +271 -0
  408. package/Tests/Types/OnCallDutyPolicy/ScheduleFirstLayer.test.ts +300 -0
  409. package/Tests/Types/OnCallDutyPolicy/ScheduleLayerDefaults.test.ts +316 -0
  410. package/Tests/Types/OnCallDutyPolicy/UserOverrideCoverRequest.test.ts +257 -0
  411. package/Tests/Types/SSO/OidcProviderDefaults.test.ts +474 -0
  412. package/Tests/Types/SSO/SamlProviderDefaults.test.ts +150 -0
  413. package/Tests/Types/SSO/SsoProviderDefaults.test.ts +181 -0
  414. package/Tests/Types/StatusPage/StatusPageAccess.test.ts +393 -0
  415. package/Tests/Types/StatusPage/StatusPagesListingMonitors.test.ts +149 -0
  416. package/Tests/Types/Telemetry/ScrubRule.test.ts +375 -0
  417. package/Tests/UI/Components/AdvancedPageSection.test.tsx +201 -61
  418. package/Tests/UI/Components/BasicFormModalSteps.test.tsx +129 -153
  419. package/Tests/UI/Components/Card.test.tsx +354 -367
  420. package/Tests/UI/Components/CardHeaderActionsGuard.test.tsx +605 -0
  421. package/Tests/UI/Components/CardModelDetailHeaderLayout.test.tsx +23 -8
  422. package/Tests/UI/Components/CardModelDetailOnBeforeUpdate.test.tsx +224 -0
  423. package/Tests/UI/Components/CardModelDetailPageButtons.test.tsx +231 -0
  424. package/Tests/UI/Components/ChoiceRows.test.tsx +365 -0
  425. package/Tests/UI/Components/CommandPalette/CommandPalette.test.tsx +341 -5
  426. package/Tests/UI/Components/CommandPalette/PaletteFilter.test.ts +655 -64
  427. package/Tests/UI/Components/Detail/DetailCreatedOnIdLine.test.tsx +669 -0
  428. package/Tests/UI/Components/Detail/DetailIdLineDarkMode.test.ts +34 -7
  429. package/Tests/UI/Components/Detail/DetailIdLineInLocale.test.tsx +71 -0
  430. package/Tests/UI/Components/Detail/DetailRecordIdLine.test.tsx +26 -7
  431. package/Tests/UI/Components/Detail/DetailRecordLine.test.tsx +326 -0
  432. package/Tests/UI/Components/Detail/DetailRecordTime.test.ts +324 -0
  433. package/Tests/UI/Components/DetailCompactStyle.test.tsx +7 -3
  434. package/Tests/UI/Components/Dropdown/DropdownChange.test.ts +163 -0
  435. package/Tests/UI/Components/EntityDropdown.test.tsx +103 -1
  436. package/Tests/UI/Components/EntityDropdownClearButton.test.tsx +638 -0
  437. package/Tests/UI/Components/EntityDropdownEscape.test.tsx +6 -6
  438. package/Tests/UI/Components/EntityDropdownFocusLeave.test.tsx +21 -4
  439. package/Tests/UI/Components/EntityDropdownQuery.test.tsx +411 -0
  440. package/Tests/UI/Components/EntityDropdownQueryHelpers.test.ts +131 -0
  441. package/Tests/UI/Components/FilePicker.test.tsx +220 -1
  442. package/Tests/UI/Components/FoldedSection/FoldedSection.test.tsx +582 -0
  443. package/Tests/UI/Components/FoldedSection/FoldedSectionDarkMode.test.ts +197 -0
  444. package/Tests/UI/Components/FoldedSection/FoldedSectionItem.test.ts +247 -0
  445. package/Tests/UI/Components/FoldedSection/FoldedSectionQueries.ts +86 -0
  446. package/Tests/UI/Components/Forms/AdvancedStepsGuard.test.ts +358 -32
  447. package/Tests/UI/Components/Forms/AnchoredFieldPopupPlacement.test.tsx +195 -0
  448. package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +187 -23
  449. package/Tests/UI/Components/Forms/BasicFormFillsInOnShow.test.tsx +246 -0
  450. package/Tests/UI/Components/Forms/BasicFormFooterSetValue.test.tsx +283 -0
  451. package/Tests/UI/Components/Forms/BasicFormPrimaryActionLastStep.test.tsx +780 -0
  452. package/Tests/UI/Components/Forms/BasicFormSingleStep.test.tsx +232 -0
  453. package/Tests/UI/Components/Forms/BasicFormStepValidation.test.tsx +7 -4
  454. package/Tests/UI/Components/Forms/BasicFormSubmitAllSteps.test.tsx +4 -3
  455. package/Tests/UI/Components/Forms/CreateFormDefaultsGuard.test.ts +252 -7
  456. package/Tests/UI/Components/Forms/DeclareAndCreateFormsGuard.test.ts +247 -7
  457. package/Tests/UI/Components/Forms/DiscoveredResourceCreateFormsGuard.test.ts +492 -0
  458. package/Tests/UI/Components/Forms/FilterConditionOnlyWithTwoFiltersGuard.test.ts +333 -0
  459. package/Tests/UI/Components/Forms/FoldedEditorWidthTiming.test.tsx +127 -0
  460. package/Tests/UI/Components/Forms/FoldedSectionsGuard.test.ts +523 -0
  461. package/Tests/UI/Components/Forms/FollowPickName.test.ts +88 -0
  462. package/Tests/UI/Components/Forms/FormFieldDropdownChange.test.tsx +294 -0
  463. package/Tests/UI/Components/Forms/FormModalWidth.test.tsx +237 -2
  464. package/Tests/UI/Components/Forms/FormSummary.test.tsx +181 -0
  465. package/Tests/UI/Components/Forms/IncidentEpisodePublicNoteNotifyPayload.test.tsx +110 -86
  466. package/Tests/UI/Components/Forms/LabelsFormFieldGuard.test.ts +101 -96
  467. package/Tests/UI/Components/Forms/LongFormStepsGuard.test.ts +559 -10
  468. package/Tests/UI/Components/Forms/MarkdownFormsAreWide.test.ts +56 -4
  469. package/Tests/UI/Components/Forms/MetricAndRecordingRuleFormsGuard.test.ts +400 -0
  470. package/Tests/UI/Components/Forms/ModelFormColorDefaults.test.tsx +659 -0
  471. package/Tests/UI/Components/Forms/ModelFormCreateDefaults.test.tsx +108 -4
  472. package/Tests/UI/Components/Forms/ModelFormDropdownQuery.test.tsx +403 -0
  473. package/Tests/UI/Components/Forms/ModelFormPreservesUserInput.test.tsx +126 -0
  474. package/Tests/UI/Components/Forms/ModelFormSinglePickPeoplePicker.test.tsx +453 -0
  475. package/Tests/UI/Components/Forms/OidcProviderFormsGuard.test.ts +321 -0
  476. package/Tests/UI/Components/Forms/OneIncidentRolePickerGuard.test.ts +823 -0
  477. package/Tests/UI/Components/Forms/OneSwitchCardsGuard.test.ts +739 -0
  478. package/Tests/UI/Components/Forms/OpenFormSections.test.tsx +169 -0
  479. package/Tests/UI/Components/Forms/OverloadedFormStepsGuard.test.ts +21 -9
  480. package/Tests/UI/Components/Forms/PrimaryActionLastStepGuard.test.ts +478 -0
  481. package/Tests/UI/Components/Forms/ProjectTeamFormsGuard.test.ts +240 -0
  482. package/Tests/UI/Components/Forms/ResourceDetailsOnePlaceGuard.test.ts +936 -0
  483. package/Tests/UI/Components/Forms/ResourceRuleFormsGuard.test.ts +527 -0
  484. package/Tests/UI/Components/Forms/SamlProviderFormsGuard.test.ts +387 -0
  485. package/Tests/UI/Components/Forms/SmallWizardsOnePageGuard.test.ts +331 -0
  486. package/Tests/UI/Components/Forms/SmtpConfigFormsGuard.test.ts +470 -0
  487. package/Tests/UI/Components/Forms/StateChangeDialogsFoldTheNote.test.ts +322 -0
  488. package/Tests/UI/Components/Forms/StatusPageResourceFormsGuard.test.ts +381 -0
  489. package/Tests/UI/Components/Forms/SteppedFormFooter.test.ts +225 -0
  490. package/Tests/UI/Components/Forms/SteppedFormFooterTiming.test.tsx +82 -40
  491. package/Tests/UI/Components/Forms/SwitchCardsGuard.test.ts +339 -0
  492. package/Tests/UI/Components/Forms/TelemetryDataRuleFormsGuard.test.ts +383 -0
  493. package/Tests/UI/Components/Forms/UniqueName.test.ts +163 -0
  494. package/Tests/UI/Components/Forms/Utils/AdvancedFormSection.test.ts +131 -11
  495. package/Tests/UI/Components/Forms/Utils/CreateFormColorDefaults.test.ts +373 -0
  496. package/Tests/UI/Components/Forms/Utils/FoldedFormFields.test.ts +482 -0
  497. package/Tests/UI/Components/LabelRuleImportExport.test.tsx +32 -0
  498. package/Tests/UI/Components/MemberRoleAssignment.test.tsx +51 -7
  499. package/Tests/UI/Components/ModalSecondaryButton.test.tsx +60 -3
  500. package/Tests/UI/Components/ModelFormDraftValues.test.tsx +255 -0
  501. package/Tests/UI/Components/ModelPageHeaderChanged.test.tsx +293 -0
  502. package/Tests/UI/Components/ModelSwitchCard.test.tsx +813 -0
  503. package/Tests/UI/Components/ModelSwitchEvents.test.ts +188 -0
  504. package/Tests/UI/Components/ModelSwitchRow.test.tsx +861 -0
  505. package/Tests/UI/Components/ModelSwitchUtil.test.ts +239 -0
  506. package/Tests/UI/Components/ModelSwitchesCard.test.tsx +699 -0
  507. package/Tests/UI/Components/NavBar.test.tsx +41 -2
  508. package/Tests/UI/Components/NavBarCategoryToggleDarkMode.test.ts +12 -0
  509. package/Tests/UI/Components/NavBarMenuCatalog.test.tsx +197 -30
  510. package/Tests/UI/Components/NavBarMenuFolding.test.tsx +221 -39
  511. package/Tests/UI/Components/NavBarMenuSearch.test.tsx +15 -10
  512. package/Tests/UI/Components/NestedControlsGuard.test.ts +300 -0
  513. package/Tests/UI/Components/PageBreadcrumbOverride.test.tsx +202 -0
  514. package/Tests/UI/Components/PeoplePicker/OwnersFieldGuard.test.ts +269 -5
  515. package/Tests/UI/Components/PeoplePicker/PeoplePickerChange.test.tsx +414 -0
  516. package/Tests/UI/Components/PeoplePicker/PeoplePickerExcludePicks.test.tsx +582 -0
  517. package/Tests/UI/Components/PeoplePicker/PeoplePickerSinglePick.test.tsx +519 -0
  518. package/Tests/UI/Components/PeoplePicker/PeoplePickerSinglePickTypes.test.ts +174 -0
  519. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +8 -3
  520. package/Tests/UI/Components/RuleCriteria/RuleCriteriaNamesGuard.test.ts +14 -6
  521. package/Tests/UI/Components/RuleRun/RuleViewDescription.test.tsx +107 -0
  522. package/Tests/UI/Components/SaveStatus.test.tsx +81 -0
  523. package/Tests/UI/Components/SmtpConfig/SmtpConfigFormFields.test.ts +1078 -0
  524. package/Tests/UI/Components/Sso/OidcProviderForm.test.tsx +608 -0
  525. package/Tests/UI/Components/Sso/OidcProviderFormFields.test.ts +698 -0
  526. package/Tests/UI/Components/Sso/SamlProviderForm.test.tsx +583 -0
  527. package/Tests/UI/Components/Sso/SamlProviderFormFields.test.ts +619 -0
  528. package/Tests/UI/Components/SteppedEditFormSave.test.tsx +199 -141
  529. package/Tests/UI/Components/Table/TableEmptyStateComponent.test.tsx +143 -0
  530. package/Tests/UI/Components/UseSaveModelSwitch.test.tsx +409 -0
  531. package/Tests/UI/Components/Workflow/ArgumentsForm.test.tsx +3 -3
  532. package/Tests/UI/Components/Workflow/ArgumentsFormAdvancedSettings.test.tsx +83 -27
  533. package/Tests/UI/Components/Workflow/WorkflowLogModal.test.tsx +7 -2
  534. package/Tests/UI/Components/useSaveOnChange.test.tsx +341 -0
  535. package/Tests/UI/Monitor/MonitorStepRetrySettings.test.tsx +1 -1
  536. package/Tests/UI/Rum/ReplayTimeline.test.tsx +75 -5
  537. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +97 -0
  538. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +12 -39
  539. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +1 -6
  540. package/Tests/{App/Dashboard → UI/Utils}/DefaultInviteTeam.test.ts +126 -4
  541. package/Tests/UI/Utils/GrantablePermission.test.ts +172 -0
  542. package/Tests/UI/Utils/PermissionGateColumnUpdate.test.ts +211 -0
  543. package/Tests/UI/Utils/TranslateTemplate.test.ts +31 -0
  544. package/Tests/Utils/DistinctColor.test.ts +446 -0
  545. package/Tests/Utils/Monitor/MonitorOverviewPresentationUtil.test.ts +14 -2
  546. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +1 -1
  547. package/Tests/Utils/NetworkDiscovery/ShortHostnameUtil.test.ts +2 -2
  548. package/Tests/Utils/Slo/SloHealth.test.ts +28 -6
  549. package/Tests/Utils/StatusPage/ReportSchedule.test.ts +867 -0
  550. package/Tests/Utils/Telemetry/DiscoveredResourceName.test.ts +189 -0
  551. package/Tests/Utils/WordMatch.test.ts +104 -0
  552. package/Types/BrandColors.ts +10 -0
  553. package/Types/CustomDomain/CustomDomainCertificates.ts +128 -0
  554. package/Types/CustomDomain/CustomDomainVerification.ts +78 -0
  555. package/Types/Dashboard/DashboardAccess.ts +250 -0
  556. package/Types/Dashboard/DashboardTemplates.ts +33 -0
  557. package/Types/Filter/FilterConditionUtil.ts +29 -0
  558. package/Types/Form/FormBranding.ts +475 -0
  559. package/Types/Form/FormPublic.ts +26 -0
  560. package/Types/IncomingCall/IncomingCallRingTime.ts +48 -0
  561. package/Types/Log/LogScrubField.ts +14 -0
  562. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +1 -1
  563. package/Types/NotificationRule/OnCallRuleKind.ts +194 -0
  564. package/Types/OnCallDutyPolicy/FirstResponders.ts +3 -32
  565. package/Types/OnCallDutyPolicy/MiscDataId.ts +38 -0
  566. package/Types/OnCallDutyPolicy/ScheduleFirstLayer.ts +165 -0
  567. package/Types/OnCallDutyPolicy/ScheduleLayerDefaults.ts +160 -0
  568. package/Types/OnCallDutyPolicy/UserOverrideCoverRequest.ts +148 -0
  569. package/Types/SSO/OidcProviderDefaults.ts +282 -0
  570. package/Types/SSO/SamlProviderDefaults.ts +77 -0
  571. package/Types/SSO/SsoProviderDefaults.ts +101 -0
  572. package/Types/StatusPage/StatusPageAccess.ts +215 -0
  573. package/Types/StatusPage/StatusPagesListingMonitors.ts +150 -0
  574. package/Types/Telemetry/ScrubRule.ts +240 -0
  575. package/UI/Components/AdvancedPageSection/AdvancedPageSection.tsx +59 -29
  576. package/UI/Components/Card/Card.tsx +139 -80
  577. package/UI/Components/ChoiceRows/ChoiceRows.tsx +249 -0
  578. package/UI/Components/CommandPalette/CommandPalette.tsx +28 -12
  579. package/UI/Components/CommandPalette/PaletteFilter.ts +962 -75
  580. package/UI/Components/CommandPalette/PaletteRow.tsx +35 -3
  581. package/UI/Components/CommandPalette/Types.ts +37 -1
  582. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +6 -0
  583. package/UI/Components/Detail/Detail.tsx +52 -15
  584. package/UI/Components/Detail/DetailRecordLine.tsx +96 -0
  585. package/UI/Components/Detail/DetailRecordTime.ts +196 -0
  586. package/UI/Components/Dropdown/DropdownChange.ts +198 -0
  587. package/UI/Components/EntityDropdown/EntityDropdown.tsx +270 -106
  588. package/UI/Components/EntityDropdown/EntityDropdownQuery.ts +119 -0
  589. package/UI/Components/FilePicker/FilePicker.tsx +90 -6
  590. package/UI/Components/FoldedSection/FoldedSection.tsx +370 -0
  591. package/UI/Components/FoldedSection/FoldedSectionItem.ts +141 -0
  592. package/UI/Components/FoldedSection/FoldedSectionTitles.ts +39 -0
  593. package/UI/Components/FormModal/BasicFormModal.tsx +40 -67
  594. package/UI/Components/Forms/BasicForm.tsx +218 -119
  595. package/UI/Components/Forms/BasicModelForm.tsx +0 -2
  596. package/UI/Components/Forms/CollapsibleFormSection.tsx +108 -18
  597. package/UI/Components/Forms/Fields/FormField.tsx +62 -15
  598. package/UI/Components/Forms/Fields/GeneratedKeyField.tsx +1 -5
  599. package/UI/Components/Forms/FormSummary.tsx +5 -3
  600. package/UI/Components/Forms/ModelForm.tsx +123 -16
  601. package/UI/Components/Forms/Types/Field.ts +98 -16
  602. package/UI/Components/Forms/Utils/AdvancedFormSection.ts +102 -31
  603. package/UI/Components/Forms/Utils/CreateFormDefaults.ts +158 -17
  604. package/UI/Components/Forms/Utils/FoldedFormFields.ts +393 -0
  605. package/UI/Components/Forms/Utils/FollowPickName.ts +52 -0
  606. package/UI/Components/Forms/Utils/FormModalWidth.ts +35 -4
  607. package/UI/Components/Forms/Utils/OpenFormSections.ts +104 -0
  608. package/UI/Components/Forms/Utils/SteppedFormFooter.ts +151 -0
  609. package/UI/Components/Forms/Utils/UniqueName.ts +81 -0
  610. package/UI/Components/LabelRule/ImportLabelRulesModal.tsx +22 -3
  611. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +6 -5
  612. package/UI/Components/Modal/ModalFooter.tsx +10 -1
  613. package/UI/Components/ModelDetail/CardModelDetail.tsx +33 -8
  614. package/UI/Components/ModelFormModal/ModelFormModal.tsx +44 -58
  615. package/UI/Components/ModelSwitch/ModelSwitchCard.tsx +305 -0
  616. package/UI/Components/ModelSwitch/ModelSwitchEvents.ts +109 -0
  617. package/UI/Components/ModelSwitch/ModelSwitchRow.tsx +438 -0
  618. package/UI/Components/ModelSwitch/ModelSwitchUtil.ts +120 -0
  619. package/UI/Components/ModelSwitch/ModelSwitchesCard.tsx +265 -0
  620. package/UI/Components/ModelSwitch/useSaveModelSwitch.ts +144 -0
  621. package/UI/Components/ModelTable/BaseModelTable.tsx +6 -0
  622. package/UI/Components/ModelTable/ModelTable.tsx +5 -0
  623. package/UI/Components/Navbar/NavBar.tsx +10 -9
  624. package/UI/Components/Navbar/NavBarMenuCatalog.ts +57 -22
  625. package/UI/Components/Navbar/NavBarMenuModal.tsx +17 -13
  626. package/UI/Components/Navbar/NavBarMobileMenu.tsx +40 -23
  627. package/UI/Components/Page/ModelHeaderEvents.ts +75 -0
  628. package/UI/Components/Page/ModelPage.tsx +21 -1
  629. package/UI/Components/Page/Page.tsx +68 -13
  630. package/UI/Components/PeoplePicker/PeoplePicker.tsx +150 -45
  631. package/UI/Components/PeoplePicker/PeoplePickerTypes.ts +193 -4
  632. package/UI/Components/PeoplePicker/PeopleSearchPopup.tsx +37 -10
  633. package/UI/Components/PublicForm/PublicFormFavicon.ts +99 -0
  634. package/UI/Components/PublicForm/PublicFormLogo.tsx +81 -0
  635. package/UI/Components/RuleCriteria/RuleCriteriaBuilder.tsx +5 -3
  636. package/UI/Components/RuleRun/RuleView.tsx +2 -5
  637. package/UI/Components/SaveStatus/SaveStatus.tsx +76 -0
  638. package/UI/Components/SaveStatus/useSaveOnChange.ts +178 -0
  639. package/UI/Components/SmtpConfig/SmtpConfigFormFields.ts +815 -0
  640. package/UI/Components/Sso/OidcProviderFormFields.ts +481 -0
  641. package/UI/Components/Sso/SamlProviderFormFields.ts +322 -0
  642. package/UI/Components/Sso/SsoProviderFormFields.ts +331 -0
  643. package/UI/Components/Table/TableEmptyState.tsx +39 -5
  644. package/UI/Components/Workflow/ArgumentsForm.tsx +21 -78
  645. package/UI/Components/Workflow/ComponentPicker/ComponentSearch.ts +18 -145
  646. package/UI/Components/Workflow/WorkflowLogModal.tsx +1 -3
  647. package/UI/Types/UseAnchoredFieldPopup.ts +46 -4
  648. package/UI/Utils/DefaultInviteTeam.ts +306 -0
  649. package/UI/Utils/GrantablePermission.ts +46 -0
  650. package/UI/Utils/PermissionGate.ts +80 -7
  651. package/UI/Utils/TranslateTemplate.ts +22 -0
  652. package/Utils/DistinctColor.ts +223 -0
  653. package/Utils/Monitor/MonitorOverviewPresentationUtil.ts +47 -2
  654. package/Utils/Slo/SloHealth.ts +9 -3
  655. package/Utils/StatusPage/ReportSchedule.ts +462 -0
  656. package/Utils/Telemetry/DiscoveredResourceName.ts +95 -0
  657. package/Utils/WordMatch.ts +185 -0
  658. package/build/dist/Models/DatabaseModels/AlertGroupingRule.js +6 -6
  659. package/build/dist/Models/DatabaseModels/AlertGroupingRule.js.map +1 -1
  660. package/build/dist/Models/DatabaseModels/File.js +47 -1
  661. package/build/dist/Models/DatabaseModels/File.js.map +1 -1
  662. package/build/dist/Models/DatabaseModels/Form.js +125 -0
  663. package/build/dist/Models/DatabaseModels/Form.js.map +1 -1
  664. package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js +6 -6
  665. package/build/dist/Models/DatabaseModels/IncidentGroupingRule.js.map +1 -1
  666. package/build/dist/Models/DatabaseModels/LogDropFilter.js +1 -0
  667. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  668. package/build/dist/Models/DatabaseModels/LogPipeline.js +1 -0
  669. package/build/dist/Models/DatabaseModels/LogPipeline.js.map +1 -1
  670. package/build/dist/Models/DatabaseModels/LogScrubRule.js +14 -8
  671. package/build/dist/Models/DatabaseModels/LogScrubRule.js.map +1 -1
  672. package/build/dist/Models/DatabaseModels/MetricRecordingRule.js +1 -1
  673. package/build/dist/Models/DatabaseModels/MetricRecordingRule.js.map +1 -1
  674. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js +2 -2
  675. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLogTimeline.js.map +1 -1
  676. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js +20 -9
  677. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js.map +1 -1
  678. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js +6 -1
  679. package/build/dist/Models/DatabaseModels/ProjectCallSMSConfig.js.map +1 -1
  680. package/build/dist/Models/DatabaseModels/StatusPage.js +4 -4
  681. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  682. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +1 -0
  683. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  684. package/build/dist/Models/DatabaseModels/TracePipeline.js +1 -0
  685. package/build/dist/Models/DatabaseModels/TracePipeline.js.map +1 -1
  686. package/build/dist/Models/DatabaseModels/TraceRecordingRule.js +1 -1
  687. package/build/dist/Models/DatabaseModels/TraceRecordingRule.js.map +1 -1
  688. package/build/dist/Models/DatabaseModels/TraceScrubRule.js +14 -8
  689. package/build/dist/Models/DatabaseModels/TraceScrubRule.js.map +1 -1
  690. package/build/dist/Models/DatabaseModels/UserOnCallLog.js +2 -2
  691. package/build/dist/Models/DatabaseModels/UserOnCallLog.js.map +1 -1
  692. package/build/dist/Server/API/CustomDomainRoutes.js +124 -0
  693. package/build/dist/Server/API/CustomDomainRoutes.js.map +1 -0
  694. package/build/dist/Server/API/DashboardAPI.js +22 -4
  695. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  696. package/build/dist/Server/API/DashboardDomainAPI.js +56 -49
  697. package/build/dist/Server/API/DashboardDomainAPI.js.map +1 -1
  698. package/build/dist/Server/API/StatusPageAPI.js +101 -39
  699. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  700. package/build/dist/Server/API/StatusPageDomainAPI.js +52 -51
  701. package/build/dist/Server/API/StatusPageDomainAPI.js.map +1 -1
  702. package/build/dist/Server/Infrastructure/GlobalCache.js +63 -0
  703. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  704. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1797700000000-AddFormBranding.js +36 -0
  705. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1797700000000-AddFormBranding.js.map +1 -0
  706. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  707. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  708. package/build/dist/Server/Services/AlertGroupingEngineService.js +44 -61
  709. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  710. package/build/dist/Server/Services/AlertGroupingRuleService.js +45 -0
  711. package/build/dist/Server/Services/AlertGroupingRuleService.js.map +1 -1
  712. package/build/dist/Server/Services/CephClusterService.js +23 -0
  713. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  714. package/build/dist/Server/Services/CloudResourceService.js +39 -0
  715. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  716. package/build/dist/Server/Services/DashboardDomainService.js +510 -172
  717. package/build/dist/Server/Services/DashboardDomainService.js.map +1 -1
  718. package/build/dist/Server/Services/DashboardService.js +22 -9
  719. package/build/dist/Server/Services/DashboardService.js.map +1 -1
  720. package/build/dist/Server/Services/DatabaseService.js +114 -10
  721. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  722. package/build/dist/Server/Services/DockerHostService.js +51 -0
  723. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  724. package/build/dist/Server/Services/DockerSwarmClusterService.js +23 -0
  725. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  726. package/build/dist/Server/Services/FileService.js +45 -0
  727. package/build/dist/Server/Services/FileService.js.map +1 -1
  728. package/build/dist/Server/Services/FormService.js +158 -14
  729. package/build/dist/Server/Services/FormService.js.map +1 -1
  730. package/build/dist/Server/Services/GlobalOidcService.js +9 -0
  731. package/build/dist/Server/Services/GlobalOidcService.js.map +1 -1
  732. package/build/dist/Server/Services/GlobalSsoService.js +9 -0
  733. package/build/dist/Server/Services/GlobalSsoService.js.map +1 -1
  734. package/build/dist/Server/Services/HostService.js +50 -0
  735. package/build/dist/Server/Services/HostService.js.map +1 -1
  736. package/build/dist/Server/Services/IncidentGroupingEngineService.js +45 -62
  737. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  738. package/build/dist/Server/Services/IncidentGroupingRuleService.js +45 -0
  739. package/build/dist/Server/Services/IncidentGroupingRuleService.js.map +1 -1
  740. package/build/dist/Server/Services/IoTFleetService.js +23 -0
  741. package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
  742. package/build/dist/Server/Services/KubernetesClusterService.js +54 -0
  743. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  744. package/build/dist/Server/Services/LabelService.js +6 -16
  745. package/build/dist/Server/Services/LabelService.js.map +1 -1
  746. package/build/dist/Server/Services/LogScrubRuleService.js +31 -0
  747. package/build/dist/Server/Services/LogScrubRuleService.js.map +1 -1
  748. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +202 -0
  749. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  750. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +7 -1
  751. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
  752. package/build/dist/Server/Services/OnCallNotificationAlertingService.js +17 -24
  753. package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -1
  754. package/build/dist/Server/Services/OnCallSetupReminderService.js +32 -38
  755. package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -1
  756. package/build/dist/Server/Services/PodmanHostService.js +51 -0
  757. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  758. package/build/dist/Server/Services/ProfileAggregationService.js +34 -0
  759. package/build/dist/Server/Services/ProfileAggregationService.js.map +1 -1
  760. package/build/dist/Server/Services/ProjectCallSMSConfigService.js +53 -3
  761. package/build/dist/Server/Services/ProjectCallSMSConfigService.js.map +1 -1
  762. package/build/dist/Server/Services/ProjectOidcService.js +28 -0
  763. package/build/dist/Server/Services/ProjectOidcService.js.map +1 -1
  764. package/build/dist/Server/Services/ProjectSsoService.js +28 -0
  765. package/build/dist/Server/Services/ProjectSsoService.js.map +1 -1
  766. package/build/dist/Server/Services/ProxmoxClusterService.js +23 -0
  767. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  768. package/build/dist/Server/Services/RumApplicationService.js +42 -0
  769. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  770. package/build/dist/Server/Services/ScheduledMaintenanceService.js +18 -26
  771. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  772. package/build/dist/Server/Services/ServerlessFunctionService.js +44 -0
  773. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  774. package/build/dist/Server/Services/ServiceService.js +30 -4
  775. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  776. package/build/dist/Server/Services/StatusPageDomainService.js +495 -174
  777. package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
  778. package/build/dist/Server/Services/StatusPageOidcService.js +28 -0
  779. package/build/dist/Server/Services/StatusPageOidcService.js.map +1 -1
  780. package/build/dist/Server/Services/StatusPageResourceService.js +82 -46
  781. package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
  782. package/build/dist/Server/Services/StatusPageService.js +174 -45
  783. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  784. package/build/dist/Server/Services/StatusPageSsoService.js +28 -0
  785. package/build/dist/Server/Services/StatusPageSsoService.js.map +1 -1
  786. package/build/dist/Server/Services/TraceScrubRuleService.js +31 -0
  787. package/build/dist/Server/Services/TraceScrubRuleService.js.map +1 -1
  788. package/build/dist/Server/Services/UserIncomingCallNumberService.js +20 -10
  789. package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -1
  790. package/build/dist/Server/Services/VMwareVCenterService.js +23 -0
  791. package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
  792. package/build/dist/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.js +3 -3
  793. package/build/dist/Server/Utils/AI/PerfEvidence/SpanTreeAnalyzer.js.map +1 -1
  794. package/build/dist/Server/Utils/Greenlock/CertificateOrder.js +353 -0
  795. package/build/dist/Server/Utils/Greenlock/CertificateOrder.js.map +1 -0
  796. package/build/dist/Server/Utils/Greenlock/CertificateOrderBudget.js +119 -0
  797. package/build/dist/Server/Utils/Greenlock/CertificateOrderBudget.js.map +1 -0
  798. package/build/dist/Server/Utils/Greenlock/CertificateOrderFailures.js +208 -0
  799. package/build/dist/Server/Utils/Greenlock/CertificateOrderFailures.js.map +1 -0
  800. package/build/dist/Server/Utils/Greenlock/CertificateOrderLock.js +111 -0
  801. package/build/dist/Server/Utils/Greenlock/CertificateOrderLock.js.map +1 -0
  802. package/build/dist/Server/Utils/Greenlock/CertificateOrderOutcome.js +30 -0
  803. package/build/dist/Server/Utils/Greenlock/CertificateOrderOutcome.js.map +1 -0
  804. package/build/dist/Server/Utils/Greenlock/CertificateOwners.js +52 -0
  805. package/build/dist/Server/Utils/Greenlock/CertificateOwners.js.map +1 -0
  806. package/build/dist/Server/Utils/Greenlock/CertificateReissueOrder.js +80 -0
  807. package/build/dist/Server/Utils/Greenlock/CertificateReissueOrder.js.map +1 -0
  808. package/build/dist/Server/Utils/Greenlock/CustomDomainOrders.js +296 -0
  809. package/build/dist/Server/Utils/Greenlock/CustomDomainOrders.js.map +1 -0
  810. package/build/dist/Server/Utils/Greenlock/Greenlock.js +595 -146
  811. package/build/dist/Server/Utils/Greenlock/Greenlock.js.map +1 -1
  812. package/build/dist/Server/Utils/Rules/GroupingRuleEpisodeOwners.js +366 -0
  813. package/build/dist/Server/Utils/Rules/GroupingRuleEpisodeOwners.js.map +1 -0
  814. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +7 -0
  815. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -1
  816. package/build/dist/Server/Utils/ScrubRuleValidation.js +127 -0
  817. package/build/dist/Server/Utils/ScrubRuleValidation.js.map +1 -0
  818. package/build/dist/Server/Utils/StatusPage/AffectedStatusPageResources.js +97 -0
  819. package/build/dist/Server/Utils/StatusPage/AffectedStatusPageResources.js.map +1 -0
  820. package/build/dist/Server/Utils/StatusPage/StatusPagesListingMonitorsBuilder.js +195 -0
  821. package/build/dist/Server/Utils/StatusPage/StatusPagesListingMonitorsBuilder.js.map +1 -0
  822. package/build/dist/Server/Utils/Telemetry/DiscoveredResourceCreate.js +177 -0
  823. package/build/dist/Server/Utils/Telemetry/DiscoveredResourceCreate.js.map +1 -0
  824. package/build/dist/Server/Utils/Telemetry/DiscoveredResourceUpdate.js +129 -0
  825. package/build/dist/Server/Utils/Telemetry/DiscoveredResourceUpdate.js.map +1 -0
  826. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +8 -2
  827. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -1
  828. package/build/dist/Types/BrandColors.js +9 -0
  829. package/build/dist/Types/BrandColors.js.map +1 -1
  830. package/build/dist/Types/CustomDomain/CustomDomainCertificates.js +71 -0
  831. package/build/dist/Types/CustomDomain/CustomDomainCertificates.js.map +1 -0
  832. package/build/dist/Types/CustomDomain/CustomDomainVerification.js +58 -0
  833. package/build/dist/Types/CustomDomain/CustomDomainVerification.js.map +1 -0
  834. package/build/dist/Types/Dashboard/DashboardAccess.js +157 -0
  835. package/build/dist/Types/Dashboard/DashboardAccess.js.map +1 -0
  836. package/build/dist/Types/Dashboard/DashboardTemplates.js +26 -0
  837. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  838. package/build/dist/Types/Filter/FilterConditionUtil.js +24 -0
  839. package/build/dist/Types/Filter/FilterConditionUtil.js.map +1 -0
  840. package/build/dist/Types/Form/FormBranding.js +266 -0
  841. package/build/dist/Types/Form/FormBranding.js.map +1 -0
  842. package/build/dist/Types/Form/FormPublic.js +6 -0
  843. package/build/dist/Types/Form/FormPublic.js.map +1 -1
  844. package/build/dist/Types/IncomingCall/IncomingCallRingTime.js +37 -0
  845. package/build/dist/Types/IncomingCall/IncomingCallRingTime.js.map +1 -0
  846. package/build/dist/Types/Log/LogScrubField.js +15 -0
  847. package/build/dist/Types/Log/LogScrubField.js.map +1 -0
  848. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +1 -1
  849. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
  850. package/build/dist/Types/NotificationRule/OnCallRuleKind.js +134 -0
  851. package/build/dist/Types/NotificationRule/OnCallRuleKind.js.map +1 -0
  852. package/build/dist/Types/OnCallDutyPolicy/FirstResponders.js +2 -23
  853. package/build/dist/Types/OnCallDutyPolicy/FirstResponders.js.map +1 -1
  854. package/build/dist/Types/OnCallDutyPolicy/MiscDataId.js +30 -0
  855. package/build/dist/Types/OnCallDutyPolicy/MiscDataId.js.map +1 -0
  856. package/build/dist/Types/OnCallDutyPolicy/ScheduleFirstLayer.js +113 -0
  857. package/build/dist/Types/OnCallDutyPolicy/ScheduleFirstLayer.js.map +1 -0
  858. package/build/dist/Types/OnCallDutyPolicy/ScheduleLayerDefaults.js +95 -0
  859. package/build/dist/Types/OnCallDutyPolicy/ScheduleLayerDefaults.js.map +1 -0
  860. package/build/dist/Types/OnCallDutyPolicy/UserOverrideCoverRequest.js +99 -0
  861. package/build/dist/Types/OnCallDutyPolicy/UserOverrideCoverRequest.js.map +1 -0
  862. package/build/dist/Types/SSO/OidcProviderDefaults.js +189 -0
  863. package/build/dist/Types/SSO/OidcProviderDefaults.js.map +1 -0
  864. package/build/dist/Types/SSO/SamlProviderDefaults.js +55 -0
  865. package/build/dist/Types/SSO/SamlProviderDefaults.js.map +1 -0
  866. package/build/dist/Types/SSO/SsoProviderDefaults.js +67 -0
  867. package/build/dist/Types/SSO/SsoProviderDefaults.js.map +1 -0
  868. package/build/dist/Types/StatusPage/StatusPageAccess.js +132 -0
  869. package/build/dist/Types/StatusPage/StatusPageAccess.js.map +1 -0
  870. package/build/dist/Types/StatusPage/StatusPagesListingMonitors.js +84 -0
  871. package/build/dist/Types/StatusPage/StatusPagesListingMonitors.js.map +1 -0
  872. package/build/dist/Types/Telemetry/ScrubRule.js +180 -0
  873. package/build/dist/Types/Telemetry/ScrubRule.js.map +1 -0
  874. package/build/dist/UI/Components/AdvancedPageSection/AdvancedPageSection.js +9 -7
  875. package/build/dist/UI/Components/AdvancedPageSection/AdvancedPageSection.js.map +1 -1
  876. package/build/dist/UI/Components/Card/Card.js +81 -35
  877. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  878. package/build/dist/UI/Components/ChoiceRows/ChoiceRows.js +54 -0
  879. package/build/dist/UI/Components/ChoiceRows/ChoiceRows.js.map +1 -0
  880. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +25 -12
  881. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  882. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js +632 -64
  883. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js.map +1 -1
  884. package/build/dist/UI/Components/CommandPalette/PaletteRow.js +7 -1
  885. package/build/dist/UI/Components/CommandPalette/PaletteRow.js.map +1 -1
  886. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +7 -1
  887. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  888. package/build/dist/UI/Components/Detail/Detail.js +26 -13
  889. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  890. package/build/dist/UI/Components/Detail/DetailRecordLine.js +32 -0
  891. package/build/dist/UI/Components/Detail/DetailRecordLine.js.map +1 -0
  892. package/build/dist/UI/Components/Detail/DetailRecordTime.js +134 -0
  893. package/build/dist/UI/Components/Detail/DetailRecordTime.js.map +1 -0
  894. package/build/dist/UI/Components/Dropdown/DropdownChange.js +102 -0
  895. package/build/dist/UI/Components/Dropdown/DropdownChange.js.map +1 -0
  896. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +134 -57
  897. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  898. package/build/dist/UI/Components/EntityDropdown/EntityDropdownQuery.js +78 -0
  899. package/build/dist/UI/Components/EntityDropdown/EntityDropdownQuery.js.map +1 -0
  900. package/build/dist/UI/Components/FilePicker/FilePicker.js +55 -6
  901. package/build/dist/UI/Components/FilePicker/FilePicker.js.map +1 -1
  902. package/build/dist/UI/Components/FoldedSection/FoldedSection.js +139 -0
  903. package/build/dist/UI/Components/FoldedSection/FoldedSection.js.map +1 -0
  904. package/build/dist/UI/Components/FoldedSection/FoldedSectionItem.js +58 -0
  905. package/build/dist/UI/Components/FoldedSection/FoldedSectionItem.js.map +1 -0
  906. package/build/dist/UI/Components/FoldedSection/FoldedSectionTitles.js +34 -0
  907. package/build/dist/UI/Components/FoldedSection/FoldedSectionTitles.js.map +1 -0
  908. package/build/dist/UI/Components/FormModal/BasicFormModal.js +29 -45
  909. package/build/dist/UI/Components/FormModal/BasicFormModal.js.map +1 -1
  910. package/build/dist/UI/Components/Forms/BasicForm.js +148 -89
  911. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  912. package/build/dist/UI/Components/Forms/BasicModelForm.js +1 -1
  913. package/build/dist/UI/Components/Forms/BasicModelForm.js.map +1 -1
  914. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +49 -10
  915. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -1
  916. package/build/dist/UI/Components/Forms/Fields/FormField.js +25 -11
  917. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  918. package/build/dist/UI/Components/Forms/Fields/GeneratedKeyField.js +2 -5
  919. package/build/dist/UI/Components/Forms/Fields/GeneratedKeyField.js.map +1 -1
  920. package/build/dist/UI/Components/Forms/FormSummary.js +5 -3
  921. package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
  922. package/build/dist/UI/Components/Forms/ModelForm.js +72 -14
  923. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  924. package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
  925. package/build/dist/UI/Components/Forms/Utils/AdvancedFormSection.js +80 -23
  926. package/build/dist/UI/Components/Forms/Utils/AdvancedFormSection.js.map +1 -1
  927. package/build/dist/UI/Components/Forms/Utils/CreateFormDefaults.js +91 -9
  928. package/build/dist/UI/Components/Forms/Utils/CreateFormDefaults.js.map +1 -1
  929. package/build/dist/UI/Components/Forms/Utils/FoldedFormFields.js +243 -0
  930. package/build/dist/UI/Components/Forms/Utils/FoldedFormFields.js.map +1 -0
  931. package/build/dist/UI/Components/Forms/Utils/FollowPickName.js +32 -0
  932. package/build/dist/UI/Components/Forms/Utils/FollowPickName.js.map +1 -0
  933. package/build/dist/UI/Components/Forms/Utils/FormModalWidth.js +25 -5
  934. package/build/dist/UI/Components/Forms/Utils/FormModalWidth.js.map +1 -1
  935. package/build/dist/UI/Components/Forms/Utils/OpenFormSections.js +32 -0
  936. package/build/dist/UI/Components/Forms/Utils/OpenFormSections.js.map +1 -0
  937. package/build/dist/UI/Components/Forms/Utils/SteppedFormFooter.js +71 -0
  938. package/build/dist/UI/Components/Forms/Utils/SteppedFormFooter.js.map +1 -0
  939. package/build/dist/UI/Components/Forms/Utils/UniqueName.js +56 -0
  940. package/build/dist/UI/Components/Forms/Utils/UniqueName.js.map +1 -0
  941. package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js +17 -1
  942. package/build/dist/UI/Components/LabelRule/ImportLabelRulesModal.js.map +1 -1
  943. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
  944. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  945. package/build/dist/UI/Components/Modal/ModalFooter.js +8 -1
  946. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  947. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +19 -6
  948. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  949. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js +33 -43
  950. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  951. package/build/dist/UI/Components/ModelSwitch/ModelSwitchCard.js +151 -0
  952. package/build/dist/UI/Components/ModelSwitch/ModelSwitchCard.js.map +1 -0
  953. package/build/dist/UI/Components/ModelSwitch/ModelSwitchEvents.js +54 -0
  954. package/build/dist/UI/Components/ModelSwitch/ModelSwitchEvents.js.map +1 -0
  955. package/build/dist/UI/Components/ModelSwitch/ModelSwitchRow.js +201 -0
  956. package/build/dist/UI/Components/ModelSwitch/ModelSwitchRow.js.map +1 -0
  957. package/build/dist/UI/Components/ModelSwitch/ModelSwitchUtil.js +60 -0
  958. package/build/dist/UI/Components/ModelSwitch/ModelSwitchUtil.js.map +1 -0
  959. package/build/dist/UI/Components/ModelSwitch/ModelSwitchesCard.js +116 -0
  960. package/build/dist/UI/Components/ModelSwitch/ModelSwitchesCard.js.map +1 -0
  961. package/build/dist/UI/Components/ModelSwitch/useSaveModelSwitch.js +68 -0
  962. package/build/dist/UI/Components/ModelSwitch/useSaveModelSwitch.js.map +1 -0
  963. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -0
  964. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  965. package/build/dist/UI/Components/ModelTable/ModelTable.js +3 -1
  966. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  967. package/build/dist/UI/Components/Navbar/NavBar.js +2 -2
  968. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  969. package/build/dist/UI/Components/Navbar/NavBarMenuCatalog.js +21 -10
  970. package/build/dist/UI/Components/Navbar/NavBarMenuCatalog.js.map +1 -1
  971. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +10 -7
  972. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  973. package/build/dist/UI/Components/Navbar/NavBarMobileMenu.js +17 -9
  974. package/build/dist/UI/Components/Navbar/NavBarMobileMenu.js.map +1 -1
  975. package/build/dist/UI/Components/Page/ModelHeaderEvents.js +43 -0
  976. package/build/dist/UI/Components/Page/ModelHeaderEvents.js.map +1 -0
  977. package/build/dist/UI/Components/Page/ModelPage.js +19 -1
  978. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  979. package/build/dist/UI/Components/Page/Page.js +31 -13
  980. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  981. package/build/dist/UI/Components/PeoplePicker/PeoplePicker.js +62 -20
  982. package/build/dist/UI/Components/PeoplePicker/PeoplePicker.js.map +1 -1
  983. package/build/dist/UI/Components/PeoplePicker/PeoplePickerTypes.js +98 -1
  984. package/build/dist/UI/Components/PeoplePicker/PeoplePickerTypes.js.map +1 -1
  985. package/build/dist/UI/Components/PeoplePicker/PeopleSearchPopup.js +35 -14
  986. package/build/dist/UI/Components/PeoplePicker/PeopleSearchPopup.js.map +1 -1
  987. package/build/dist/UI/Components/PublicForm/PublicFormFavicon.js +66 -0
  988. package/build/dist/UI/Components/PublicForm/PublicFormFavicon.js.map +1 -0
  989. package/build/dist/UI/Components/PublicForm/PublicFormLogo.js +38 -0
  990. package/build/dist/UI/Components/PublicForm/PublicFormLogo.js.map +1 -0
  991. package/build/dist/UI/Components/RuleCriteria/RuleCriteriaBuilder.js +5 -3
  992. package/build/dist/UI/Components/RuleCriteria/RuleCriteriaBuilder.js.map +1 -1
  993. package/build/dist/UI/Components/RuleRun/RuleView.js +2 -2
  994. package/build/dist/UI/Components/RuleRun/RuleView.js.map +1 -1
  995. package/build/dist/UI/Components/SaveStatus/SaveStatus.js +46 -0
  996. package/build/dist/UI/Components/SaveStatus/SaveStatus.js.map +1 -0
  997. package/build/dist/UI/Components/SaveStatus/useSaveOnChange.js +98 -0
  998. package/build/dist/UI/Components/SaveStatus/useSaveOnChange.js.map +1 -0
  999. package/build/dist/UI/Components/SmtpConfig/SmtpConfigFormFields.js +503 -0
  1000. package/build/dist/UI/Components/SmtpConfig/SmtpConfigFormFields.js.map +1 -0
  1001. package/build/dist/UI/Components/Sso/OidcProviderFormFields.js +283 -0
  1002. package/build/dist/UI/Components/Sso/OidcProviderFormFields.js.map +1 -0
  1003. package/build/dist/UI/Components/Sso/SamlProviderFormFields.js +182 -0
  1004. package/build/dist/UI/Components/Sso/SamlProviderFormFields.js.map +1 -0
  1005. package/build/dist/UI/Components/Sso/SsoProviderFormFields.js +208 -0
  1006. package/build/dist/UI/Components/Sso/SsoProviderFormFields.js.map +1 -0
  1007. package/build/dist/UI/Components/Table/TableEmptyState.js +17 -4
  1008. package/build/dist/UI/Components/Table/TableEmptyState.js.map +1 -1
  1009. package/build/dist/UI/Components/Workflow/ArgumentsForm.js +17 -52
  1010. package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
  1011. package/build/dist/UI/Components/Workflow/ComponentPicker/ComponentSearch.js +7 -89
  1012. package/build/dist/UI/Components/Workflow/ComponentPicker/ComponentSearch.js.map +1 -1
  1013. package/build/dist/UI/Components/Workflow/WorkflowLogModal.js +1 -1
  1014. package/build/dist/UI/Components/Workflow/WorkflowLogModal.js.map +1 -1
  1015. package/build/dist/UI/Types/UseAnchoredFieldPopup.js +22 -3
  1016. package/build/dist/UI/Types/UseAnchoredFieldPopup.js.map +1 -1
  1017. package/build/dist/UI/Utils/DefaultInviteTeam.js +207 -0
  1018. package/build/dist/UI/Utils/DefaultInviteTeam.js.map +1 -0
  1019. package/build/dist/UI/Utils/GrantablePermission.js +31 -0
  1020. package/build/dist/UI/Utils/GrantablePermission.js.map +1 -1
  1021. package/build/dist/UI/Utils/PermissionGate.js +54 -3
  1022. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  1023. package/build/dist/UI/Utils/TranslateTemplate.js +16 -0
  1024. package/build/dist/UI/Utils/TranslateTemplate.js.map +1 -1
  1025. package/build/dist/Utils/DistinctColor.js +151 -0
  1026. package/build/dist/Utils/DistinctColor.js.map +1 -0
  1027. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js +12 -1
  1028. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js.map +1 -1
  1029. package/build/dist/Utils/Slo/SloHealth.js +9 -3
  1030. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  1031. package/build/dist/Utils/StatusPage/ReportSchedule.js +304 -0
  1032. package/build/dist/Utils/StatusPage/ReportSchedule.js.map +1 -0
  1033. package/build/dist/Utils/Telemetry/DiscoveredResourceName.js +65 -0
  1034. package/build/dist/Utils/Telemetry/DiscoveredResourceName.js.map +1 -0
  1035. package/build/dist/Utils/WordMatch.js +115 -0
  1036. package/build/dist/Utils/WordMatch.js.map +1 -0
  1037. package/package.json +1 -1
  1038. package/Tests/App/Dashboard/BulkChangeStateModalSteps.test.ts +0 -109
  1039. package/Tests/App/StatusPage/StatusPageSubscribeFromFirstStep.test.tsx +0 -382
  1040. package/Tests/UI/Components/Forms/BasicFormFinishFromAnyStep.test.tsx +0 -729
  1041. package/Tests/UI/Components/Forms/FinishFromAnyStep.test.ts +0 -571
  1042. package/Tests/UI/Components/Forms/FinishFromAnyStepGuard.test.ts +0 -566
  1043. package/UI/Components/Forms/Utils/FinishFromAnyStep.ts +0 -284
  1044. package/build/dist/UI/Components/Forms/Utils/FinishFromAnyStep.js +0 -132
  1045. package/build/dist/UI/Components/Forms/Utils/FinishFromAnyStep.js.map +0 -1
@@ -8,7 +8,6 @@ import AcmeChallengeService from "../../Services/AcmeChallengeService";
8
8
  import QueryHelper from "../../Types/Database/QueryHelper";
9
9
  import logger, { LogAttributes } from "../Logger";
10
10
  import SortOrder from "../../../Types/BaseDatabase/SortOrder";
11
- import LIMIT_MAX from "../../../Types/Database/LimitMax";
12
11
  import OneUptimeDate from "../../../Types/Date";
13
12
  import BadDataException from "../../../Types/Exception/BadDataException";
14
13
  import Exception from "../../../Types/Exception/Exception";
@@ -16,10 +15,19 @@ import ServerException from "../../../Types/Exception/ServerException";
16
15
  import Text from "../../../Types/Text";
17
16
  import AcmeCertificate from "../../../Models/DatabaseModels/AcmeCertificate";
18
17
  import AcmeChallenge from "../../../Models/DatabaseModels/AcmeChallenge";
18
+ import LIMIT_MAX from "../../../Types/Database/LimitMax";
19
19
  import ArrayUtil from "../../../Utils/Array";
20
20
  import acme from "acme-client";
21
21
  import { Challenge } from "acme-client/types/rfc8555";
22
22
  import CaptureSpan from "../Telemetry/CaptureSpan";
23
+ import CertificateOrderLock, {
24
+ CertificateOrderLockHandle,
25
+ } from "./CertificateOrderLock";
26
+ import CertificateOrderBudget, {
27
+ CertificateOrderReason,
28
+ } from "./CertificateOrderBudget";
29
+ import CertificateOrderFailures from "./CertificateOrderFailures";
30
+ import { CertificateOrderOutcome } from "./CertificateOrderOutcome";
23
31
 
24
32
  export default class GreenlockUtil {
25
33
  /*
@@ -54,6 +62,29 @@ export default class GreenlockUtil {
54
62
  public static readonly RENEW_MAX_PER_RUN: number = 10;
55
63
  public static readonly RENEW_CONCURRENCY: number = 5;
56
64
 
65
+ /*
66
+ * Lookups by domain name (an owner asked which domains are its own, the
67
+ * certificates of a list of domains) take at most this many names at once,
68
+ * so a long list becomes several short IN (...) lookups rather than one
69
+ * statement with thousands of parameters.
70
+ */
71
+ public static readonly DOMAIN_LOOKUP_CHUNK_SIZE: number = 500;
72
+
73
+ /*
74
+ * A certificate nobody owns is deleted once it has been expired this long,
75
+ * at most REMOVE_UNOWNED_MAX_PER_RUN per run.
76
+ *
77
+ * Such certificates are left behind when a project, status page, dashboard
78
+ * or parent domain is deleted: those deletes remove the domain rows through
79
+ * the database's ON DELETE CASCADE, which skips the hook that removes the
80
+ * certificate. An expired certificate serves nobody, and every owner orders
81
+ * a fresh one when its own is missing, so deleting one cannot take a
82
+ * working domain down. The month of grace is for a domain that is deleted
83
+ * and added back.
84
+ */
85
+ public static readonly REMOVE_UNOWNED_AFTER_EXPIRY_IN_DAYS: number = 30;
86
+ public static readonly REMOVE_UNOWNED_MAX_PER_RUN: number = 100;
87
+
57
88
  /*
58
89
  * Stable per-domain lead time, somewhere in the range above. Same domain,
59
90
  * same answer, on every run and every replica.
@@ -74,10 +105,224 @@ export default class GreenlockUtil {
74
105
  );
75
106
  }
76
107
 
108
+ /*
109
+ * Whether this certificate has reached its own renewal lead time. Expired
110
+ * certificates are due too.
111
+ */
112
+ public static isDueForRenewal(
113
+ certificate: { domain?: string | undefined; expiresAt?: Date | undefined },
114
+ now: Date,
115
+ ): boolean {
116
+ if (!certificate.domain || !certificate.expiresAt) {
117
+ return false;
118
+ }
119
+
120
+ const renewAt: Date = OneUptimeDate.addRemoveDays(
121
+ certificate.expiresAt,
122
+ -GreenlockUtil.getRenewalLeadTimeInDays(certificate.domain),
123
+ );
124
+
125
+ return !OneUptimeDate.isAfter(renewAt, now);
126
+ }
127
+
128
+ /*
129
+ * The items a capped sweep works on in this run: at most max of them,
130
+ * chosen by a shuffle that is the same for every replica within one
131
+ * 15-minute window and different in the next, so an item whose work keeps
132
+ * failing cannot hold a slot run after run while the others wait. Every
133
+ * item has the same chance in every run, however the list grows, shrinks
134
+ * or is ordered, and whatever schedule the sweep runs on - a fixed
135
+ * rotation would skip items whenever earlier ones left the list.
136
+ */
137
+ public static pickForThisRun<T>(data: {
138
+ items: Array<T>;
139
+ max: number;
140
+ now: Date;
141
+ getKey: (item: T) => string;
142
+ }): Array<T> {
143
+ const max: number = Math.max(Math.floor(data.max), 0);
144
+
145
+ const window: number = Math.floor(
146
+ data.now.getTime() / OneUptimeDate.convertMinutesToMilliseconds(15),
147
+ );
148
+
149
+ return data.items
150
+ .map((item: T) => {
151
+ const key: string = data.getKey(item);
152
+
153
+ return {
154
+ item: item,
155
+ key: key,
156
+ rank:
157
+ data.items.length <= max
158
+ ? 0
159
+ : GreenlockUtil.hashText(`${window}:${key}`),
160
+ };
161
+ })
162
+ .sort(
163
+ (
164
+ a: { key: string; rank: number },
165
+ b: { key: string; rank: number },
166
+ ) => {
167
+ if (a.rank !== b.rank) {
168
+ return a.rank - b.rank;
169
+ }
170
+
171
+ if (a.key === b.key) {
172
+ return 0;
173
+ }
174
+
175
+ return a.key < b.key ? -1 : 1;
176
+ },
177
+ )
178
+ .slice(0, max)
179
+ .map((ranked: { item: T }) => {
180
+ return ranked.item;
181
+ });
182
+ }
183
+
184
+ // 32-bit FNV-1a: a stable, well-spread hash of a string.
185
+ private static hashText(text: string): number {
186
+ let hash: number = 0x811c9dc5;
187
+
188
+ for (let i: number = 0; i < text.length; i++) {
189
+ hash ^= text.charCodeAt(i);
190
+ hash = Math.imul(hash, 0x01000193) >>> 0;
191
+ }
192
+
193
+ return hash;
194
+ }
195
+
196
+ /*
197
+ * The certificate each of these domains has in AcmeCertificate, if any,
198
+ * looked up DOMAIN_LOOKUP_CHUNK_SIZE names at a time. Where a name has more
199
+ * than one row, the one that expires last. A row without an expiry is no
200
+ * certificate at all: it is never due, so nothing would ever replace it if
201
+ * it counted as one.
202
+ *
203
+ * The sweeps that order first certificates and re-order missing ones read
204
+ * this to tell a domain that needs an order from one that only needs to be
205
+ * recorded as ordered.
206
+ */
207
+ @CaptureSpan()
208
+ public static async findCertificatesByDomain(
209
+ domains: Array<string>,
210
+ ): Promise<Map<string, AcmeCertificate>> {
211
+ const certificates: Map<string, AcmeCertificate> = new Map<
212
+ string,
213
+ AcmeCertificate
214
+ >();
215
+
216
+ const uniqueDomains: Array<string> = Array.from(
217
+ new Set<string>(
218
+ domains.filter((domain: string) => {
219
+ return domain.length > 0;
220
+ }),
221
+ ),
222
+ );
223
+
224
+ for (
225
+ let offset: number = 0;
226
+ offset < uniqueDomains.length;
227
+ offset += GreenlockUtil.DOMAIN_LOOKUP_CHUNK_SIZE
228
+ ) {
229
+ const chunk: Array<string> = uniqueDomains.slice(
230
+ offset,
231
+ offset + GreenlockUtil.DOMAIN_LOOKUP_CHUNK_SIZE,
232
+ );
233
+
234
+ const rows: Array<AcmeCertificate> = await AcmeCertificateService.findBy({
235
+ query: {
236
+ domain: QueryHelper.any(chunk),
237
+ },
238
+ select: {
239
+ domain: true,
240
+ expiresAt: true,
241
+ },
242
+ limit: LIMIT_MAX,
243
+ skip: 0,
244
+ props: {
245
+ isRoot: true,
246
+ },
247
+ });
248
+
249
+ for (const row of rows) {
250
+ if (!row.domain || !row.expiresAt) {
251
+ continue;
252
+ }
253
+
254
+ const existing: AcmeCertificate | undefined = certificates.get(
255
+ row.domain,
256
+ );
257
+
258
+ if (
259
+ !existing ||
260
+ OneUptimeDate.isAfter(row.expiresAt, existing.expiresAt as Date)
261
+ ) {
262
+ certificates.set(row.domain, row);
263
+ }
264
+ }
265
+ }
266
+
267
+ return certificates;
268
+ }
269
+
270
+ /*
271
+ * Ask one owner which of these domains are its own, a chunk at a time.
272
+ */
273
+ private static async getOwnedAmong(data: {
274
+ domains: Array<string>;
275
+ getOwnedDomains: (domains: Array<string>) => Promise<Array<string>>;
276
+ }): Promise<Set<string>> {
277
+ const owned: Set<string> = new Set<string>();
278
+ const domains: Array<string> = Array.from(new Set<string>(data.domains));
279
+
280
+ for (
281
+ let offset: number = 0;
282
+ offset < domains.length;
283
+ offset += GreenlockUtil.DOMAIN_LOOKUP_CHUNK_SIZE
284
+ ) {
285
+ const chunk: Array<string> = domains.slice(
286
+ offset,
287
+ offset + GreenlockUtil.DOMAIN_LOOKUP_CHUNK_SIZE,
288
+ );
289
+
290
+ for (const domain of await data.getOwnedDomains(chunk)) {
291
+ owned.add(domain);
292
+ }
293
+ }
294
+
295
+ return owned;
296
+ }
297
+
298
+ /*
299
+ * Renew the caller's certificates that are due, at most maxPerRun of them
300
+ * per run (RENEW_MAX_PER_RUN unless the caller asks for fewer).
301
+ *
302
+ * AcmeCertificate is one table shared by every owner of a certificate:
303
+ * status page domains, dashboard domains and the installation's own
304
+ * primary host (CoreSSL). Each owner runs this on its own schedule and can
305
+ * only judge its own domains - its validateCname reports false for every
306
+ * domain it has no row for. So a run must never act on a certificate it
307
+ * does not own. Before getOwnedDomains existed, the status page run
308
+ * treated every dashboard certificate (and the primary host's, whenever
309
+ * its lead time came before CoreSSL's 30-day renewal) as a status page
310
+ * whose CNAME had stopped validating, and deleted it.
311
+ *
312
+ * getOwnedDomains is handed the due domains (a chunk at a time) and
313
+ * returns the ones the caller owns. Every due certificate is read, not a
314
+ * first page of them, and ownership is settled before the cap, so neither
315
+ * another owner's backlog nor a pile of expired certificates nobody owns
316
+ * can take this caller's slots. A certificate nobody claims is left exactly
317
+ * as it is: neither renewed nor removed
318
+ * (removeExpiredCertificatesNobodyOwns cleans those up once they are dead).
319
+ */
77
320
  @CaptureSpan()
78
321
  public static async renewAllCertsWhichAreExpiringSoon(data: {
322
+ getOwnedDomains: (domains: Array<string>) => Promise<Array<string>>;
79
323
  validateCname: (domain: string) => Promise<boolean>;
80
324
  notifyDomainRemoved: (domain: string) => Promise<void>;
325
+ maxPerRun?: number | undefined;
81
326
  }): Promise<void> {
82
327
  try {
83
328
  logger.debug("Renewing all certificates");
@@ -87,7 +332,7 @@ export default class GreenlockUtil {
87
332
  * keep only the domains whose own lead time has actually been reached.
88
333
  */
89
334
  const certificates: AcmeCertificate[] =
90
- await AcmeCertificateService.findBy({
335
+ await AcmeCertificateService.findAllBy({
91
336
  query: {
92
337
  expiresAt: QueryHelper.lessThanEqualTo(
93
338
  OneUptimeDate.addRemoveDays(
@@ -96,7 +341,6 @@ export default class GreenlockUtil {
96
341
  ),
97
342
  ),
98
343
  },
99
- limit: LIMIT_MAX,
100
344
  skip: 0,
101
345
  select: {
102
346
  domain: true,
@@ -112,35 +356,115 @@ export default class GreenlockUtil {
112
356
 
113
357
  const now: Date = OneUptimeDate.getCurrentDate();
114
358
 
359
+ /*
360
+ * One renewal per name: a name can have more than one row, and a row
361
+ * renewed between two page reads can come back on both.
362
+ */
363
+ const dueDomains: Set<string> = new Set<string>();
364
+
115
365
  const dueCertificates: AcmeCertificate[] = certificates.filter(
116
366
  (certificate: AcmeCertificate) => {
117
- if (!certificate.domain || !certificate.expiresAt) {
367
+ if (
368
+ !GreenlockUtil.isDueForRenewal(certificate, now) ||
369
+ dueDomains.has(certificate.domain as string)
370
+ ) {
118
371
  return false;
119
372
  }
120
373
 
121
- const renewAt: Date = OneUptimeDate.addRemoveDays(
122
- certificate.expiresAt,
123
- -GreenlockUtil.getRenewalLeadTimeInDays(certificate.domain),
124
- );
374
+ dueDomains.add(certificate.domain as string);
375
+ return true;
376
+ },
377
+ );
125
378
 
126
- return !OneUptimeDate.isAfter(renewAt, now);
379
+ /*
380
+ * A lookup that fails throws out of the run before anything is renewed
381
+ * or removed: not knowing who owns a certificate is never a reason to
382
+ * touch it.
383
+ */
384
+ const ownedDomains: Set<string> = await GreenlockUtil.getOwnedAmong({
385
+ domains: dueCertificates.map((certificate: AcmeCertificate) => {
386
+ return certificate.domain as string;
387
+ }),
388
+ getOwnedDomains: data.getOwnedDomains,
389
+ });
390
+
391
+ const ownedDueCertificates: AcmeCertificate[] = dueCertificates.filter(
392
+ (certificate: AcmeCertificate) => {
393
+ return ownedDomains.has(certificate.domain as string);
127
394
  },
128
395
  );
129
396
 
397
+ /*
398
+ * A name whose last renewals failed - a CAA record that leaves Let's
399
+ * Encrypt out, a name Let's Encrypt has paused - waits longer after
400
+ * each failure in a row (CertificateOrderFailures) instead of taking a
401
+ * slot in every run. Each failed order counts against the account all
402
+ * the same, and Let's Encrypt allows five failed validations per name
403
+ * per hour.
404
+ */
405
+ const renewableDueCertificates: AcmeCertificate[] =
406
+ await CertificateOrderFailures.withoutThoseWaitingToRetry({
407
+ items: ownedDueCertificates,
408
+ getDomain: (certificate: AcmeCertificate): string => {
409
+ return certificate.domain as string;
410
+ },
411
+ now: now,
412
+ });
413
+
414
+ const maxPerRun: number = Math.max(
415
+ Math.min(
416
+ data.maxPerRun ?? GreenlockUtil.RENEW_MAX_PER_RUN,
417
+ GreenlockUtil.RENEW_MAX_PER_RUN,
418
+ ),
419
+ 0,
420
+ );
421
+
130
422
  /*
131
423
  * Still sorted by expiry, so a run that cannot take the whole backlog
132
424
  * spends itself on the domains closest to expiring and leaves the rest -
133
425
  * which by construction still have weeks of lead time - to the next run.
426
+ *
427
+ * Certificates that have already expired come after every one that can
428
+ * still be saved, and take turns among themselves. Such a domain has
429
+ * been failing to renew since its lead time began - a CAA record that
430
+ * leaves Let's Encrypt out, a name Let's Encrypt has paused - and,
431
+ * sorting first by expiry, it would otherwise take a slot in every run
432
+ * and starve the renewals behind it. It is still tried whenever slots
433
+ * are left, which in a run without a backlog is every run.
134
434
  */
135
- const batch: AcmeCertificate[] = dueCertificates.slice(
136
- 0,
137
- GreenlockUtil.RENEW_MAX_PER_RUN,
435
+ const stillValid: AcmeCertificate[] = renewableDueCertificates.filter(
436
+ (certificate: AcmeCertificate) => {
437
+ return OneUptimeDate.isAfter(certificate.expiresAt as Date, now);
438
+ },
439
+ );
440
+
441
+ const alreadyExpired: AcmeCertificate[] = renewableDueCertificates.filter(
442
+ (certificate: AcmeCertificate) => {
443
+ return !OneUptimeDate.isAfter(certificate.expiresAt as Date, now);
444
+ },
138
445
  );
139
446
 
447
+ const firstInLine: AcmeCertificate[] = stillValid.slice(0, maxPerRun);
448
+
449
+ const batch: AcmeCertificate[] = [
450
+ ...firstInLine,
451
+ ...GreenlockUtil.pickForThisRun({
452
+ items: alreadyExpired,
453
+ max: maxPerRun - firstInLine.length,
454
+ now: now,
455
+ getKey: (certificate: AcmeCertificate): string => {
456
+ return certificate.domain as string;
457
+ },
458
+ }),
459
+ ];
460
+
140
461
  logger.debug(
141
- `Found ${dueCertificates.length} certificates due for renewal, renewing ${batch.length} in this run`,
462
+ `Found ${dueCertificates.length} certificates due for renewal, ${ownedDueCertificates.length} of them owned by this caller, ${ownedDueCertificates.length - renewableDueCertificates.length} of those waiting after failed orders, renewing ${batch.length} in this run`,
142
463
  {
143
464
  dueCount: dueCertificates.length,
465
+ ownedDueCount: ownedDueCertificates.length,
466
+ waitingAfterFailureCount:
467
+ ownedDueCertificates.length - renewableDueCertificates.length,
144
468
  batchCount: batch.length,
145
469
  },
146
470
  );
@@ -164,10 +488,136 @@ export default class GreenlockUtil {
164
488
  }
165
489
  }
166
490
 
491
+ /*
492
+ * Delete certificates that have been expired for more than
493
+ * REMOVE_UNOWNED_AFTER_EXPIRY_IN_DAYS and that no owner claims, at most
494
+ * REMOVE_UNOWNED_MAX_PER_RUN per run. Returns how many were deleted.
495
+ *
496
+ * owners must name every kind of certificate owner there is (see
497
+ * CertificateOwners). A certificate is deleted only when all of them have
498
+ * answered and none claims it; if any lookup fails, nothing is deleted.
499
+ *
500
+ * The delete names the row's id AND that it is still expired, and
501
+ * hardDeleteBy keeps those conditions in the DELETE statement itself:
502
+ * orderCert renews a name by updating its row in place, so a row renewed at
503
+ * any point before the delete no longer matches and is kept. A newer row for
504
+ * the same name never matches either.
505
+ */
506
+ @CaptureSpan()
507
+ public static async removeExpiredCertificatesNobodyOwns(data: {
508
+ owners: Array<{
509
+ name: string;
510
+ getOwnedDomains: (domains: Array<string>) => Promise<Array<string>>;
511
+ }>;
512
+ }): Promise<number> {
513
+ const expiredBefore: Date = OneUptimeDate.addRemoveDays(
514
+ OneUptimeDate.getCurrentDate(),
515
+ -GreenlockUtil.REMOVE_UNOWNED_AFTER_EXPIRY_IN_DAYS,
516
+ );
517
+
518
+ const expiredCertificates: Array<AcmeCertificate> =
519
+ await AcmeCertificateService.findAllBy({
520
+ query: {
521
+ expiresAt: QueryHelper.lessThan(expiredBefore),
522
+ },
523
+ select: {
524
+ _id: true,
525
+ domain: true,
526
+ expiresAt: true,
527
+ },
528
+ sort: {
529
+ expiresAt: SortOrder.Ascending,
530
+ },
531
+ skip: 0,
532
+ props: {
533
+ isRoot: true,
534
+ },
535
+ });
536
+
537
+ const candidates: Array<AcmeCertificate> = expiredCertificates.filter(
538
+ (certificate: AcmeCertificate) => {
539
+ return Boolean(certificate.domain) && Boolean(certificate.id);
540
+ },
541
+ );
542
+
543
+ if (candidates.length === 0) {
544
+ return 0;
545
+ }
546
+
547
+ const domains: Array<string> = candidates.map(
548
+ (certificate: AcmeCertificate) => {
549
+ return certificate.domain as string;
550
+ },
551
+ );
552
+
553
+ const ownedDomains: Set<string> = new Set<string>();
554
+
555
+ for (const owner of data.owners) {
556
+ const ownedByThisOwner: Set<string> = await GreenlockUtil.getOwnedAmong({
557
+ domains: domains,
558
+ getOwnedDomains: owner.getOwnedDomains,
559
+ });
560
+
561
+ for (const domain of ownedByThisOwner) {
562
+ ownedDomains.add(domain);
563
+ }
564
+ }
565
+
566
+ const abandoned: Array<AcmeCertificate> = candidates
567
+ .filter((certificate: AcmeCertificate) => {
568
+ return !ownedDomains.has(certificate.domain as string);
569
+ })
570
+ .slice(0, GreenlockUtil.REMOVE_UNOWNED_MAX_PER_RUN);
571
+
572
+ let removedCount: number = 0;
573
+
574
+ for (const certificate of abandoned) {
575
+ logger.debug(
576
+ `Deleting the certificate of ${certificate.domain}: it expired on ${certificate.expiresAt?.toISOString()} and no status page, dashboard or primary host claims it.`,
577
+ { domain: certificate.domain } as LogAttributes,
578
+ );
579
+
580
+ const deletedCount: number = await AcmeCertificateService.hardDeleteBy({
581
+ query: {
582
+ _id: certificate.id!.toString(),
583
+ domain: certificate.domain as string,
584
+ expiresAt: QueryHelper.lessThan(expiredBefore),
585
+ },
586
+ limit: 1,
587
+ skip: 0,
588
+ props: {
589
+ isRoot: true,
590
+ },
591
+ });
592
+
593
+ removedCount += deletedCount;
594
+ }
595
+
596
+ return removedCount;
597
+ }
598
+
167
599
  /*
168
600
  * Renew one domain. Never throws: one domain that cannot be renewed - a CNAME
169
601
  * that no longer points here, a challenge the CA would not accept - must not
170
602
  * take down the rest of the run with it.
603
+ *
604
+ * The renewal runs with the name's order lock held, so it never overlaps a
605
+ * reissue, a Check now or a re-order of the same name, and it looks the
606
+ * certificate up again under that lock: one of those may have replaced it
607
+ * since this run read the table, and renewing it again would spend an
608
+ * order on a duplicate.
609
+ *
610
+ * A CNAME check that fails never deletes a certificate that is still
611
+ * valid. It used to, and a moment's DNS trouble during a renewal took a
612
+ * domain off HTTPS with weeks left on its certificate. Now the renewal is
613
+ * skipped while the certificate keeps serving, and the failure is
614
+ * recorded (CertificateOrderFailures): the domain's Status column says so,
615
+ * and the name waits before the next attempt, longer after each failure
616
+ * in a row - without that, a domain whose record really is gone would take
617
+ * a slot of every run until its certificate expired, and keep the
618
+ * renewals behind it waiting. Only a certificate that has already expired
619
+ * - it serves nobody - is removed when the check fails, so the domain is
620
+ * ordered afresh once its record is back.
171
621
  */
172
622
  private static async renewCertForDomain(data: {
173
623
  domain: string;
@@ -185,43 +635,98 @@ export default class GreenlockUtil {
185
635
  certLogAttributes,
186
636
  );
187
637
 
638
+ const lock: CertificateOrderLockHandle | null =
639
+ await CertificateOrderLock.tryLock(domain);
640
+
641
+ if (!lock) {
642
+ logger.debug(
643
+ `Not renewing the certificate of ${domain} now: another order for it is running. A later run renews it if it is still due.`,
644
+ certLogAttributes,
645
+ );
646
+ return;
647
+ }
648
+
188
649
  try {
189
- //validate cname
190
- const isValidCname: boolean = await data.validateCname(domain);
650
+ const now: Date = OneUptimeDate.getCurrentDate();
191
651
 
192
- if (!isValidCname) {
652
+ const certificate: AcmeCertificate | undefined = (
653
+ await GreenlockUtil.findCertificatesByDomain([lock.domain])
654
+ ).get(lock.domain);
655
+
656
+ if (!certificate) {
193
657
  logger.debug(
194
- `CNAME is not valid for domain: ${domain}`,
658
+ `Not renewing the certificate of ${domain}: it is gone. The domain's owner re-orders a missing certificate.`,
195
659
  certLogAttributes,
196
660
  );
661
+ return;
662
+ }
197
663
 
198
- // if cname is not valid then remove the domain
199
- await GreenlockUtil.removeDomain(domain);
200
- await data.notifyDomainRemoved(domain);
201
-
202
- logger.error(
203
- `Cname is not valid for domain: ${domain}`,
664
+ if (!GreenlockUtil.isDueForRenewal(certificate, now)) {
665
+ logger.debug(
666
+ `Not renewing the certificate of ${domain}: another order has renewed it since this run started.`,
204
667
  certLogAttributes,
205
668
  );
206
- } else {
207
- logger.debug(`CNAME is valid for domain: ${domain}`, certLogAttributes);
669
+ return;
670
+ }
208
671
 
209
- await GreenlockUtil.orderCert({
210
- domain: domain,
211
- validateCname: data.validateCname,
212
- });
672
+ const isValidCname: boolean = await data.validateCname(domain);
673
+
674
+ if (!isValidCname) {
675
+ const hasExpired: boolean = !OneUptimeDate.isAfter(
676
+ certificate.expiresAt as Date,
677
+ now,
678
+ );
679
+
680
+ if (!hasExpired) {
681
+ logger.debug(
682
+ `CNAME of ${domain} did not validate: keeping its certificate, valid until ${certificate.expiresAt?.toISOString()}, and renewing it on a later run.`,
683
+ certLogAttributes,
684
+ );
685
+
686
+ await CertificateOrderFailures.record({
687
+ domain: domain,
688
+ error: `We could not renew the certificate of ${lock.domain} because its CNAME record could not be verified. The certificate keeps serving until it expires; please check that the record still points to OneUptime.`,
689
+ now: now,
690
+ });
691
+
692
+ return;
693
+ }
213
694
 
214
695
  logger.debug(
215
- `Certificate renewed for domain: ${domain}`,
696
+ `CNAME of ${domain} did not validate and its certificate has expired: removing the certificate.`,
216
697
  certLogAttributes,
217
698
  );
699
+
700
+ await GreenlockUtil.removeDomain(domain);
701
+ await data.notifyDomainRemoved(domain);
702
+
703
+ return;
218
704
  }
705
+
706
+ logger.debug(`CNAME is valid for domain: ${domain}`, certLogAttributes);
707
+
708
+ const outcome: CertificateOrderOutcome = await GreenlockUtil.orderCert({
709
+ domain: domain,
710
+ reason: CertificateOrderReason.Renewal,
711
+ // Checked a moment ago, above.
712
+ validateCname: null,
713
+ lock: lock,
714
+ });
715
+
716
+ logger.debug(
717
+ outcome === CertificateOrderOutcome.Ordered
718
+ ? `Certificate renewed for domain: ${domain}`
719
+ : `Certificate of ${domain} not renewed now (${outcome}): a later run renews it.`,
720
+ certLogAttributes,
721
+ );
219
722
  } catch (e) {
220
723
  logger.error(
221
724
  `Error renewing certificate for domain: ${domain}`,
222
725
  certLogAttributes,
223
726
  );
224
727
  logger.error(e, certLogAttributes);
728
+ } finally {
729
+ await CertificateOrderLock.release(lock);
225
730
  }
226
731
  }
227
732
 
@@ -245,43 +750,111 @@ export default class GreenlockUtil {
245
750
  }
246
751
  }
247
752
 
753
+ /*
754
+ * Order a certificate for a name from Let's Encrypt and store it. Every
755
+ * certificate this installation orders is ordered here, whoever asks -
756
+ * Check now, the sweeps, the order and reissue APIs, the renewal runs and
757
+ * CoreSSL - so what must hold for every order holds here:
758
+ *
759
+ * - One order per name at a time. The order runs under the name's lock
760
+ * (CertificateOrderLock): the one the caller hands in, or one taken
761
+ * here. A name whose lock is taken is not ordered (NotOrderedNow).
762
+ * - The installation's Let's Encrypt allowance. Each order takes one unit
763
+ * of CertificateOrderBudget for its reason, and none is placed when
764
+ * there is none left (LimitReached).
765
+ * - Nothing is deleted. A CNAME check that fails refuses the order and
766
+ * leaves the name's certificate as it is. It used to remove it, so a
767
+ * DNS blip during a reissue, a renewal or a dashboard order took a
768
+ * working domain off HTTPS.
769
+ * - A failed order is recorded (CertificateOrderFailures) for the
770
+ * domain's Status column and the retry delay of the sweeps, and a
771
+ * successful one clears that record.
772
+ *
773
+ * Throws when the CNAME check fails or the order fails, with a message the
774
+ * caller can show.
775
+ */
248
776
  @CaptureSpan()
249
777
  public static async orderCert(data: {
250
778
  domain: string;
251
- validateCname: (domain: string) => Promise<boolean>;
252
- }): Promise<void> {
253
- const orderLogAttributes: LogAttributes = {
254
- domain: data.domain,
255
- };
779
+ reason: CertificateOrderReason;
780
+ /*
781
+ * Checks, before anything is spent, that the domain still points here:
782
+ * an order for a name whose record is gone only fails, and counts as a
783
+ * failed validation. Null when the caller has just checked it - a second
784
+ * check only gives a DNS blip one more chance to refuse an order the
785
+ * first check allowed.
786
+ */
787
+ validateCname: ((domain: string) => Promise<boolean>) | null;
788
+ // The name's order lock, when the caller holds it already.
789
+ lock?: CertificateOrderLockHandle | undefined;
790
+ /*
791
+ * The caller's own share of orders - a sweep's budget, the on-demand
792
+ * one - asked once the CNAME check has passed and before the
793
+ * installation's budget, so a share is not spent on a domain whose
794
+ * record is gone. False orders nothing (LimitReached).
795
+ */
796
+ mayOrder?: (() => Promise<boolean>) | undefined;
797
+ }): Promise<CertificateOrderOutcome> {
798
+ const domain: string = CertificateOrderLock.normalizeDomain(data.domain);
256
799
 
257
- try {
258
- logger.debug(
259
- `GreenlockUtil - Ordering certificate for domain: ${data.domain}`,
260
- orderLogAttributes,
261
- );
800
+ if (data.lock && !CertificateOrderLock.isHeldFor(data.lock, domain)) {
801
+ /*
802
+ * Redis lost the lock while the caller held it: another order of the
803
+ * name may be running now. Not the caller's mistake - just not now.
804
+ */
805
+ if (CertificateOrderLock.wasLost(data.lock, domain)) {
806
+ logger.debug(
807
+ `Not ordering a certificate for ${domain}: the lock on the name was lost before the order`,
808
+ { domain: domain } as LogAttributes,
809
+ );
262
810
 
263
- let { domain } = data;
811
+ return CertificateOrderOutcome.NotOrderedNow;
812
+ }
264
813
 
265
- domain = domain.trim().toLowerCase();
266
- orderLogAttributes["domain"] = domain;
814
+ throw new BadDataException(
815
+ `The certificate order lock handed in for ${domain} is not held.`,
816
+ );
817
+ }
267
818
 
268
- const acmeAccountKeyInBase64: string = LetsEncryptAccountKey;
819
+ const lock: CertificateOrderLockHandle | null =
820
+ data.lock || (await CertificateOrderLock.tryLock(domain));
269
821
 
270
- if (!acmeAccountKeyInBase64) {
271
- throw new ServerException(
272
- "No lets encrypt account key found in environment variables. Please add one.",
273
- );
822
+ if (!lock) {
823
+ return CertificateOrderOutcome.NotOrderedNow;
824
+ }
825
+
826
+ try {
827
+ return await GreenlockUtil.orderCertWithLockHeld({
828
+ domain: domain,
829
+ reason: data.reason,
830
+ validateCname: data.validateCname,
831
+ mayOrder: data.mayOrder,
832
+ });
833
+ } finally {
834
+ if (!data.lock) {
835
+ await CertificateOrderLock.release(lock);
274
836
  }
837
+ }
838
+ }
275
839
 
276
- let acmeAccountKey: string = Buffer.from(
277
- acmeAccountKeyInBase64,
278
- "base64",
279
- ).toString();
840
+ private static async orderCertWithLockHeld(data: {
841
+ domain: string;
842
+ reason: CertificateOrderReason;
843
+ validateCname: ((domain: string) => Promise<boolean>) | null;
844
+ mayOrder?: (() => Promise<boolean>) | undefined;
845
+ }): Promise<CertificateOrderOutcome> {
846
+ const { domain } = data;
280
847
 
281
- acmeAccountKey = Text.replaceAll(acmeAccountKey, "\\n", "\n");
848
+ const orderLogAttributes: LogAttributes = {
849
+ domain: domain,
850
+ };
282
851
 
283
- //validate cname
852
+ logger.debug(
853
+ `GreenlockUtil - Ordering certificate for domain: ${domain} (${data.reason})`,
854
+ orderLogAttributes,
855
+ );
284
856
 
857
+ if (data.validateCname) {
285
858
  logger.debug(
286
859
  `Validating cname for domain: ${domain}`,
287
860
  orderLogAttributes,
@@ -290,139 +863,221 @@ export default class GreenlockUtil {
290
863
  const isValidCname: boolean = await data.validateCname(domain);
291
864
 
292
865
  if (!isValidCname) {
293
- logger.debug(
294
- `CNAME is not valid for domain: ${domain}`,
295
- orderLogAttributes,
296
- );
297
- logger.debug(`Removing domain: ${domain}`, orderLogAttributes);
298
-
299
- await GreenlockUtil.removeDomain(domain);
300
866
  logger.error(
301
- `Cname is not valid for domain: ${domain}`,
867
+ `Cname is not valid for domain: ${domain}. Not ordering, and keeping its certificate, if it has one.`,
302
868
  orderLogAttributes,
303
869
  );
870
+
304
871
  throw new BadDataException("Cname is not valid for domain " + domain);
305
872
  }
306
873
 
307
874
  logger.debug(`Cname is valid for domain: ${domain}`, orderLogAttributes);
875
+ }
308
876
 
309
- const client: acme.Client = new acme.Client({
310
- directoryUrl: acme.directory.letsencrypt.production,
311
- accountKey: acmeAccountKey,
877
+ if (data.mayOrder && !(await data.mayOrder())) {
878
+ logger.debug(
879
+ `Not ordering a certificate for ${domain} now: this window's orders of its kind are used up`,
880
+ orderLogAttributes,
881
+ );
882
+
883
+ return CertificateOrderOutcome.LimitReached;
884
+ }
885
+
886
+ try {
887
+ const acmeAccountKeyInBase64: string = LetsEncryptAccountKey;
888
+
889
+ if (!acmeAccountKeyInBase64) {
890
+ throw new ServerException(
891
+ "No lets encrypt account key found in environment variables. Please add one.",
892
+ );
893
+ }
894
+
895
+ if (
896
+ !(await CertificateOrderBudget.takeSlot({
897
+ reason: data.reason,
898
+ now: OneUptimeDate.getCurrentDate(),
899
+ domain: domain,
900
+ }))
901
+ ) {
902
+ return CertificateOrderOutcome.LimitReached;
903
+ }
904
+
905
+ await GreenlockUtil.orderAndStoreCertificate({
906
+ domain: domain,
907
+ acmeAccountKeyInBase64: acmeAccountKeyInBase64,
908
+ orderLogAttributes: orderLogAttributes,
312
909
  });
910
+ } catch (e) {
911
+ logger.error(
912
+ `Error ordering certificate for domain: ${domain}`,
913
+ orderLogAttributes,
914
+ );
915
+ logger.error(e, orderLogAttributes);
916
+
917
+ const error: Exception = GreenlockUtil.toOrderError(e, domain);
313
918
 
314
- const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
315
- commonName: domain,
919
+ await CertificateOrderFailures.record({
920
+ domain: domain,
921
+ error: error.message,
922
+ now: OneUptimeDate.getCurrentDate(),
316
923
  });
317
924
 
318
- logger.debug(
319
- `Ordering certificate for domain: ${domain}`,
320
- orderLogAttributes,
925
+ throw error;
926
+ }
927
+
928
+ await CertificateOrderFailures.clear(domain);
929
+
930
+ return CertificateOrderOutcome.Ordered;
931
+ }
932
+
933
+ // What the caller of a failed order is told.
934
+ private static toOrderError(e: unknown, domain: string): Exception {
935
+ if (e instanceof Exception) {
936
+ return e;
937
+ }
938
+
939
+ if (IsBillingEnabled) {
940
+ return new ServerException(
941
+ `Unable to order certificate for ${domain}. Please contact support at support@oneuptime.com for more information.`,
321
942
  );
943
+ }
322
944
 
323
- const certificate: string = await client.auto({
324
- csr: certificateRequest,
325
- email: LetsEncryptNotificationEmail.toString(),
326
- termsOfServiceAgreed: true,
327
- challengePriority: ["http-01"], // only http-01 challenge is supported by oneuptime
328
- challengeCreateFn: async (
329
- authz: acme.Authorization,
330
- challenge: Challenge,
331
- keyAuthorization: string,
332
- ) => {
333
- // Satisfy challenge here
334
- /* http-01 */
335
- if (challenge.type === "http-01") {
336
- logger.debug(
337
- `Creating challenge for domain: ${authz.identifier.value}`,
338
- orderLogAttributes,
339
- );
340
-
341
- const acmeChallenge: AcmeChallenge = new AcmeChallenge();
342
- acmeChallenge.challenge = keyAuthorization;
343
- acmeChallenge.token = challenge.token;
344
- acmeChallenge.domain = authz.identifier.value;
345
-
346
- await AcmeChallengeService.create({
347
- data: acmeChallenge,
348
- props: {
349
- isRoot: true,
350
- },
351
- });
352
-
353
- logger.debug(
354
- `Challenge created for domain: ${authz.identifier.value}`,
355
- orderLogAttributes,
356
- );
357
- }
358
- },
359
- challengeRemoveFn: async (
360
- authz: acme.Authorization,
361
- challenge: Challenge,
362
- ) => {
363
- // Clean up challenge here
945
+ return new ServerException(
946
+ `Unable to order certificate for ${domain}. Please make sure that your server can be accessed publicly over port 80 (HTTP) and port 443 (HTTPS). If the problem persists, please refer to server logs for more information. Please also set up LOG_LEVEL=DEBUG to get more detailed server logs.`,
947
+ );
948
+ }
949
+
950
+ private static async orderAndStoreCertificate(data: {
951
+ domain: string;
952
+ acmeAccountKeyInBase64: string;
953
+ orderLogAttributes: LogAttributes;
954
+ }): Promise<void> {
955
+ const { domain, orderLogAttributes } = data;
956
+
957
+ let acmeAccountKey: string = Buffer.from(
958
+ data.acmeAccountKeyInBase64,
959
+ "base64",
960
+ ).toString();
961
+
962
+ acmeAccountKey = Text.replaceAll(acmeAccountKey, "\\n", "\n");
364
963
 
964
+ const client: acme.Client = new acme.Client({
965
+ directoryUrl: acme.directory.letsencrypt.production,
966
+ accountKey: acmeAccountKey,
967
+ });
968
+
969
+ const [certificateKey, certificateRequest] = await acme.crypto.createCsr({
970
+ commonName: domain,
971
+ });
972
+
973
+ logger.debug(
974
+ `Ordering certificate for domain: ${domain}`,
975
+ orderLogAttributes,
976
+ );
977
+
978
+ const certificate: string = await client.auto({
979
+ csr: certificateRequest,
980
+ email: LetsEncryptNotificationEmail.toString(),
981
+ termsOfServiceAgreed: true,
982
+ challengePriority: ["http-01"], // only http-01 challenge is supported by oneuptime
983
+ challengeCreateFn: async (
984
+ authz: acme.Authorization,
985
+ challenge: Challenge,
986
+ keyAuthorization: string,
987
+ ) => {
988
+ // Satisfy challenge here
989
+ /* http-01 */
990
+ if (challenge.type === "http-01") {
365
991
  logger.debug(
366
- `Removing challenge for domain: ${authz.identifier.value}`,
992
+ `Creating challenge for domain: ${authz.identifier.value}`,
367
993
  orderLogAttributes,
368
994
  );
369
995
 
370
- if (challenge.type === "http-01") {
371
- await AcmeChallengeService.deleteBy({
372
- query: {
373
- domain: authz.identifier.value,
374
- },
375
- limit: 1,
376
- skip: 0,
377
- props: {
378
- isRoot: true,
379
- },
380
- });
381
- }
996
+ const acmeChallenge: AcmeChallenge = new AcmeChallenge();
997
+ acmeChallenge.challenge = keyAuthorization;
998
+ acmeChallenge.token = challenge.token;
999
+ acmeChallenge.domain = authz.identifier.value;
1000
+
1001
+ await AcmeChallengeService.create({
1002
+ data: acmeChallenge,
1003
+ props: {
1004
+ isRoot: true,
1005
+ },
1006
+ });
382
1007
 
383
1008
  logger.debug(
384
- `Challenge removed for domain: ${authz.identifier.value}`,
1009
+ `Challenge created for domain: ${authz.identifier.value}`,
385
1010
  orderLogAttributes,
386
1011
  );
387
- },
388
- });
389
-
390
- logger.debug(
391
- `Certificate ordered for domain: ${domain}`,
392
- orderLogAttributes,
393
- );
1012
+ }
1013
+ },
1014
+ challengeRemoveFn: async (
1015
+ authz: acme.Authorization,
1016
+ challenge: Challenge,
1017
+ ) => {
1018
+ // Clean up challenge here
394
1019
 
395
- // get expires at date from certificate
396
- const cert: acme.CertificateInfo =
397
- acme.crypto.readCertificateInfo(certificate);
398
- const issuedAt: Date = cert.notBefore;
399
- const expiresAt: Date = cert.notAfter;
400
-
401
- logger.debug(`Certificate expires at: ${expiresAt}`, orderLogAttributes);
402
- logger.debug(`Certificate issued at: ${issuedAt}`, orderLogAttributes);
1020
+ logger.debug(
1021
+ `Removing challenge for domain: ${authz.identifier.value}`,
1022
+ orderLogAttributes,
1023
+ );
403
1024
 
404
- // check if the certificate is already in the database.
405
- const existingCertificate: AcmeCertificate | null =
406
- await AcmeCertificateService.findOneBy({
407
- query: {
408
- domain: domain,
409
- },
410
- select: {
411
- _id: true,
412
- },
413
- props: {
414
- isRoot: true,
415
- },
416
- });
1025
+ if (challenge.type === "http-01") {
1026
+ await AcmeChallengeService.deleteBy({
1027
+ query: {
1028
+ domain: authz.identifier.value,
1029
+ },
1030
+ limit: 1,
1031
+ skip: 0,
1032
+ props: {
1033
+ isRoot: true,
1034
+ },
1035
+ });
1036
+ }
417
1037
 
418
- if (existingCertificate) {
419
1038
  logger.debug(
420
- `Updating certificate for domain: ${domain}`,
1039
+ `Challenge removed for domain: ${authz.identifier.value}`,
421
1040
  orderLogAttributes,
422
1041
  );
1042
+ },
1043
+ });
423
1044
 
424
- // update the certificate
425
- await AcmeCertificateService.updateBy({
1045
+ logger.debug(
1046
+ `Certificate ordered for domain: ${domain}`,
1047
+ orderLogAttributes,
1048
+ );
1049
+
1050
+ // get expires at date from certificate
1051
+ const cert: acme.CertificateInfo =
1052
+ acme.crypto.readCertificateInfo(certificate);
1053
+ const issuedAt: Date = cert.notBefore;
1054
+ const expiresAt: Date = cert.notAfter;
1055
+
1056
+ logger.debug(`Certificate expires at: ${expiresAt}`, orderLogAttributes);
1057
+ logger.debug(`Certificate issued at: ${issuedAt}`, orderLogAttributes);
1058
+
1059
+ // check if the certificate is already in the database.
1060
+ const existingCertificate: AcmeCertificate | null =
1061
+ await AcmeCertificateService.findOneBy({
1062
+ query: {
1063
+ domain: domain,
1064
+ },
1065
+ select: {
1066
+ _id: true,
1067
+ },
1068
+ props: {
1069
+ isRoot: true,
1070
+ },
1071
+ });
1072
+
1073
+ /*
1074
+ * The row can be removed between the look-up above and this write (a
1075
+ * domain deleted meanwhile, or the cleanup of expired certificates
1076
+ * nobody owned). Then the update finds nothing, and the certificate
1077
+ * the CA has just issued is stored in a new row instead of being lost.
1078
+ */
1079
+ const updatedCount: number = existingCertificate
1080
+ ? await AcmeCertificateService.updateBy({
426
1081
  query: {
427
1082
  domain: domain,
428
1083
  },
@@ -437,58 +1092,39 @@ export default class GreenlockUtil {
437
1092
  props: {
438
1093
  isRoot: true,
439
1094
  },
440
- });
1095
+ })
1096
+ : 0;
441
1097
 
442
- logger.debug(
443
- `Certificate updated for domain: ${domain}`,
444
- orderLogAttributes,
445
- );
446
- } else {
447
- logger.debug(
448
- `Creating certificate for domain: ${domain}`,
449
- orderLogAttributes,
450
- );
451
- // create the certificate
452
- const acmeCertificate: AcmeCertificate = new AcmeCertificate();
1098
+ if (updatedCount > 0) {
1099
+ logger.debug(
1100
+ `Certificate updated for domain: ${domain}`,
1101
+ orderLogAttributes,
1102
+ );
1103
+ } else {
1104
+ logger.debug(
1105
+ `Creating certificate for domain: ${domain}`,
1106
+ orderLogAttributes,
1107
+ );
1108
+ // create the certificate
1109
+ const acmeCertificate: AcmeCertificate = new AcmeCertificate();
453
1110
 
454
- acmeCertificate.domain = domain;
455
- acmeCertificate.certificate = certificate.toString();
456
- acmeCertificate.certificateKey = certificateKey.toString();
457
- acmeCertificate.issuedAt = issuedAt;
458
- acmeCertificate.expiresAt = expiresAt;
1111
+ acmeCertificate.domain = domain;
1112
+ acmeCertificate.certificate = certificate.toString();
1113
+ acmeCertificate.certificateKey = certificateKey.toString();
1114
+ acmeCertificate.issuedAt = issuedAt;
1115
+ acmeCertificate.expiresAt = expiresAt;
459
1116
 
460
- await AcmeCertificateService.create({
461
- data: acmeCertificate,
462
- props: {
463
- isRoot: true,
464
- },
465
- });
1117
+ await AcmeCertificateService.create({
1118
+ data: acmeCertificate,
1119
+ props: {
1120
+ isRoot: true,
1121
+ },
1122
+ });
466
1123
 
467
- logger.debug(
468
- `Certificate created for domain: ${domain}`,
469
- orderLogAttributes,
470
- );
471
- }
472
- } catch (e) {
473
- logger.error(
474
- `Error ordering certificate for domain: ${data.domain}`,
1124
+ logger.debug(
1125
+ `Certificate created for domain: ${domain}`,
475
1126
  orderLogAttributes,
476
1127
  );
477
- logger.error(e, orderLogAttributes);
478
-
479
- if (e instanceof Exception) {
480
- throw e;
481
- }
482
-
483
- if (IsBillingEnabled) {
484
- throw new ServerException(
485
- `Unable to order certificate for ${data.domain}. Please contact support at support@oneuptime.com for more information.`,
486
- );
487
- } else {
488
- throw new ServerException(
489
- `Unable to order certificate for ${data.domain}. Please make sure that your server can be accessed publicly over port 80 (HTTP) and port 443 (HTTPS). If the problem persists, please refer to server logs for more information. Please also set up LOG_LEVEL=DEBUG to get more detailed server logs.`,
490
- );
491
- }
492
1128
  }
493
1129
  }
494
1130
  }