@oneuptime/common 13.0.8 → 14.0.1

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 (514) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Index.ts +4 -0
  4. package/Models/DatabaseModels/Monitor.ts +3 -2
  5. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  6. package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
  7. package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
  8. package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
  9. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
  10. package/Scripts/generate-service-worker.js +65 -4
  11. package/Server/API/BaseAPI.ts +26 -5
  12. package/Server/API/GlobalConfigAPI.ts +228 -462
  13. package/Server/API/ProjectOIDC.ts +25 -16
  14. package/Server/API/ProjectSSO.ts +24 -16
  15. package/Server/API/StatusPageAPI.ts +100 -42
  16. package/Server/API/TeamMemberAPI.ts +10 -1
  17. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  18. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  19. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  20. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  21. package/Server/EnvironmentConfig.ts +147 -2
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  26. package/Server/Middleware/UserAuthorization.ts +38 -16
  27. package/Server/Services/AuditLogService.ts +84 -1079
  28. package/Server/Services/DatabaseService.ts +10 -0
  29. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  30. package/Server/Services/GlobalConfigService.ts +80 -1
  31. package/Server/Services/Index.ts +4 -0
  32. package/Server/Services/MonitorProbeService.ts +116 -20
  33. package/Server/Services/MonitorService.ts +59 -6
  34. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  35. package/Server/Services/MonitorTemplateService.ts +26 -0
  36. package/Server/Services/ProjectService.ts +284 -0
  37. package/Server/Services/RumSessionPinService.ts +25 -6
  38. package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
  39. package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
  40. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
  41. package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
  42. package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
  43. package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
  44. package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
  45. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  46. package/Server/Services/StatusPageService.ts +78 -1
  47. package/Server/Services/TeamMemberService.ts +11 -0
  48. package/Server/Services/TeamService.ts +10 -0
  49. package/Server/Services/UserService.ts +10 -17
  50. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  51. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  52. package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
  53. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  54. package/Server/Types/Markdown.ts +41 -0
  55. package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
  56. package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
  57. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  58. package/Server/Utils/EditionEnforcement.ts +233 -0
  59. package/Server/Utils/FrontendEnvironment.ts +41 -2
  60. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  61. package/Server/Utils/Monitor/AffectedResourceList.ts +148 -0
  62. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
  63. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  64. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
  65. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +720 -465
  66. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  67. package/Server/Utils/Monitor/RootCauseList.ts +139 -0
  68. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
  69. package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
  70. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  71. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  72. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  73. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  74. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  75. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  76. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  77. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  78. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  79. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  80. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  81. package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
  82. package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
  83. package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
  84. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  85. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
  86. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
  87. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  88. package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
  89. package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
  90. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
  91. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
  92. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
  93. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
  94. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  95. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  96. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
  97. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  98. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  99. package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
  100. package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
  101. package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
  102. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
  103. package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
  104. package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
  105. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  106. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  107. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  108. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  109. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
  110. package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
  111. package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
  112. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  113. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  114. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  115. package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
  116. package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
  117. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  118. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  119. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  120. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  121. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  122. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  123. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  124. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  125. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  126. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  127. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  128. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  129. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  130. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  131. package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
  132. package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
  133. package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
  134. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  135. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  136. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  137. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  138. package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
  139. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  140. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  141. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  142. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  143. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  144. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  145. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  146. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
  147. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
  148. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  149. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
  150. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
  151. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
  152. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
  153. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
  154. package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
  155. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
  156. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  157. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  158. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
  159. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  160. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  161. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  162. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
  163. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  164. package/Tests/Server/Types/Markdown.test.ts +183 -1
  165. package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
  166. package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
  167. package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
  168. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  169. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  170. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  171. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  172. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  173. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  174. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
  175. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +1339 -96
  176. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
  177. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
  178. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  179. package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
  180. package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
  181. package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
  182. package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
  183. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
  184. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  185. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  186. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  187. package/Tests/Types/API/Route.test.ts +56 -0
  188. package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
  189. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  190. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  191. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  192. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
  193. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  194. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  195. package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
  196. package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
  197. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  198. package/Tests/UI/Components/Icon.test.tsx +26 -0
  199. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  200. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  201. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  202. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  203. package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
  204. package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
  205. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  206. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  207. package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
  208. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  209. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  210. package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
  211. package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
  212. package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
  213. package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
  214. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  215. package/Types/API/Hostname.ts +63 -16
  216. package/Types/API/Route.ts +19 -2
  217. package/Types/API/URL.ts +26 -2
  218. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  219. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  220. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  221. package/Types/Database/CanonicalModelInstance.ts +102 -0
  222. package/Types/Database/TableColumn.ts +20 -6
  223. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  224. package/Types/IP/IPv6.ts +6 -1
  225. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
  226. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
  227. package/Types/Monitor/MonitorStep.ts +6 -1
  228. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  229. package/Types/Permission.ts +90 -0
  230. package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
  231. package/Types/Rules/RuleRun.ts +4 -0
  232. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  233. package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
  234. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  235. package/UI/Components/Feed/FeedOptions.ts +427 -0
  236. package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
  237. package/UI/Components/Feed/useFeedItems.ts +28 -9
  238. package/UI/Components/Feed/useFeedOptions.ts +225 -0
  239. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  240. package/UI/Components/Icon/Icon.tsx +1 -1
  241. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  242. package/UI/Components/ModelList/ModelList.tsx +11 -1
  243. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  244. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  245. package/UI/esbuild-enterprise.js +263 -0
  246. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  247. package/Utils/HostAddressUtil.ts +94 -0
  248. package/Utils/LabelRuleImportExport.ts +27 -9
  249. package/Utils/Monitor/MetricValueFormatter.ts +2 -2
  250. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  251. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  252. package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
  253. package/Utils/Slo/SloDuration.ts +22 -6
  254. package/Utils/Slo/SloHealth.ts +8 -7
  255. package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
  256. package/Utils/Slo/SloOverviewText.ts +33 -0
  257. package/Utils/Slo/SloProjection.ts +4 -3
  258. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  259. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  260. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  261. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  262. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  263. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  264. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  265. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  266. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  267. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  268. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  269. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
  270. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
  271. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
  272. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
  273. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
  274. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
  275. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
  276. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
  277. package/build/dist/Server/API/BaseAPI.js +26 -5
  278. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  279. package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
  280. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  281. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  282. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  283. package/build/dist/Server/API/ProjectSSO.js +24 -16
  284. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  285. package/build/dist/Server/API/StatusPageAPI.js +93 -43
  286. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  287. package/build/dist/Server/API/TeamMemberAPI.js +8 -1
  288. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  289. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  290. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  291. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  292. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  293. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  294. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  295. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  296. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  297. package/build/dist/Server/EnvironmentConfig.js +84 -2
  298. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  299. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  300. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  301. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
  302. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
  303. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
  304. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
  305. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  306. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  307. package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
  308. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  309. package/build/dist/Server/Services/AuditLogService.js +71 -740
  310. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  311. package/build/dist/Server/Services/DatabaseService.js +7 -0
  312. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  313. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  314. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  315. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  316. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  317. package/build/dist/Server/Services/Index.js +4 -0
  318. package/build/dist/Server/Services/Index.js.map +1 -1
  319. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  320. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  321. package/build/dist/Server/Services/MonitorService.js +48 -6
  322. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  323. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  324. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  325. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  326. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  327. package/build/dist/Server/Services/ProjectService.js +214 -0
  328. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  329. package/build/dist/Server/Services/RumSessionPinService.js +24 -6
  330. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  331. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
  332. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
  333. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
  334. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
  335. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
  336. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
  337. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
  338. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
  339. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
  340. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
  341. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
  342. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
  343. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
  344. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  345. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  346. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  347. package/build/dist/Server/Services/StatusPageService.js +71 -0
  348. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  349. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  350. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  351. package/build/dist/Server/Services/TeamService.js +9 -0
  352. package/build/dist/Server/Services/TeamService.js.map +1 -1
  353. package/build/dist/Server/Services/UserService.js +10 -16
  354. package/build/dist/Server/Services/UserService.js.map +1 -1
  355. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  356. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  357. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  358. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  359. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
  360. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  361. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  362. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  363. package/build/dist/Server/Types/Markdown.js +31 -0
  364. package/build/dist/Server/Types/Markdown.js.map +1 -1
  365. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
  366. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
  367. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
  368. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
  369. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  370. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  371. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  372. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  373. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  374. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  375. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  376. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  377. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +67 -0
  378. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  379. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
  380. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  381. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  382. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
  383. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +585 -367
  384. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  385. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  386. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  387. package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
  388. package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
  389. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
  390. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  391. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
  392. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
  393. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  394. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  395. package/build/dist/Types/API/Hostname.js +59 -11
  396. package/build/dist/Types/API/Hostname.js.map +1 -1
  397. package/build/dist/Types/API/Route.js +18 -2
  398. package/build/dist/Types/API/Route.js.map +1 -1
  399. package/build/dist/Types/API/URL.js +23 -2
  400. package/build/dist/Types/API/URL.js.map +1 -1
  401. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  402. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  403. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  404. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  405. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  406. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  407. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  408. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  409. package/build/dist/Types/Database/TableColumn.js +19 -6
  410. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  411. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  412. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  413. package/build/dist/Types/IP/IPv6.js +6 -1
  414. package/build/dist/Types/IP/IPv6.js.map +1 -1
  415. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  416. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  417. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  418. package/build/dist/Types/Permission.js +84 -0
  419. package/build/dist/Types/Permission.js.map +1 -1
  420. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
  421. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  422. package/build/dist/Types/Rules/RuleRun.js +4 -0
  423. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  424. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  425. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  426. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
  427. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  428. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  429. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  430. package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
  431. package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
  432. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
  433. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
  434. package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
  435. package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
  436. package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
  437. package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
  438. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  439. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  440. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  441. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  442. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  443. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  444. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  445. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  446. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  447. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  448. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  449. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  450. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  451. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  452. package/build/dist/Utils/HostAddressUtil.js +80 -0
  453. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  454. package/build/dist/Utils/LabelRuleImportExport.js +22 -6
  455. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  456. package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
  457. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  458. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  459. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  460. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  461. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
  462. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
  463. package/build/dist/Utils/Slo/SloDuration.js +13 -5
  464. package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
  465. package/build/dist/Utils/Slo/SloHealth.js +8 -7
  466. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  467. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
  468. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
  469. package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
  470. package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
  471. package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
  472. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  473. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  474. package/jest.config.json +3 -1
  475. package/package.json +1 -1
  476. package/test-setup.sh +103 -34
  477. package/tsconfig.json +13 -0
  478. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  479. package/Server/API/TeamComplianceAPI.ts +0 -158
  480. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  481. package/Server/Services/TeamComplianceService.ts +0 -733
  482. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  483. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  484. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  485. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  486. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
  487. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  488. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  489. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
  490. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  491. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  492. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  493. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  494. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  495. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  496. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  497. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  498. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  499. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  500. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  501. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  502. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  503. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  504. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  505. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  506. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  507. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  508. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  509. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  510. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  511. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  512. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  513. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  514. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -0,0 +1,304 @@
1
+ import MonitoringIntervalUtil, {
2
+ MonitoringIntervalNormalization,
3
+ MonitoringIntervalNormalizationStatus,
4
+ } from "../../../Utils/Monitor/MonitoringIntervalUtil";
5
+ import CronTab from "../../../Utils/CronTab";
6
+ import { describe, expect, test } from "@jest/globals";
7
+
8
+ /*
9
+ * WHAT THIS FILE IS DEFENDING
10
+ *
11
+ * Monitor.monitoringInterval is free-text and was never validated. Rows
12
+ * accumulated holding a human cadence ("5m", "Every 5 minutes") where a cron
13
+ * expression was expected. cron-parser threw on those, the claim query
14
+ * caught the throw and fell back to "one minute from now", and a monitor
15
+ * configured for five minutes was probed every ~75 seconds — four times the
16
+ * requested rate, silently, for as long as the row existed.
17
+ *
18
+ * 103 monitors across 10 projects were in that state. The ten distinct bad
19
+ * values below are the REAL production census, not invented examples, and
20
+ * every one of them is asserted individually.
21
+ */
22
+
23
+ function normalize(value: string | null | undefined): string | null {
24
+ return MonitoringIntervalUtil.toCronOrNull(value);
25
+ }
26
+
27
+ describe("MonitoringIntervalUtil", () => {
28
+ describe("the production census — every bad value found in the wild", () => {
29
+ /*
30
+ * SELECT "monitoringInterval", count(*) FROM "Monitor"
31
+ * WHERE "deletedAt" IS NULL AND "monitoringInterval" is not cron
32
+ * 103 rows, 10 distinct values, 10 projects.
33
+ */
34
+ const PRODUCTION_VALUES: Array<[string, string, number]> = [
35
+ ["Every 5 minutes", "*/5 * * * *", 35],
36
+ ["5m", "*/5 * * * *", 19],
37
+ ["1 minute", "* * * * *", 18],
38
+ ["Every 5 Minutes", "*/5 * * * *", 14],
39
+ ["Every 1 minute", "* * * * *", 6],
40
+ ["Every 2 minutes", "*/2 * * * *", 4],
41
+ ["5 minutes", "*/5 * * * *", 3],
42
+ ["1 day", "0 0 * * *", 2],
43
+ ["every-1-min", "* * * * *", 1],
44
+ ["Every Five Minutes", "*/5 * * * *", 1],
45
+ ];
46
+
47
+ test.each(PRODUCTION_VALUES)(
48
+ "reads %j as %j (%i monitors in production)",
49
+ (input: string, expectedCron: string) => {
50
+ expect(normalize(input)).toBe(expectedCron);
51
+ },
52
+ );
53
+
54
+ test("every production value now yields a parseable cron", () => {
55
+ for (const [input] of PRODUCTION_VALUES) {
56
+ const cron: string | null = normalize(input);
57
+
58
+ /*
59
+ * "Every Five Minutes" spells its number out, which the duration
60
+ * grammar cannot read. It is covered by the exact-label table; if
61
+ * that entry is ever dropped this assertion is what catches it.
62
+ */
63
+ expect(cron).not.toBeNull();
64
+ expect(CronTab.isValid(cron as string)).toBe(true);
65
+ }
66
+ });
67
+
68
+ test("the customer's value is five minutes apart, not one", () => {
69
+ /*
70
+ * The regression in one line: "5m" must not mean "every minute".
71
+ */
72
+ expect(normalize("5m")).toBe("*/5 * * * *");
73
+ expect(normalize("5m")).not.toBe("* * * * *");
74
+ });
75
+ });
76
+
77
+ describe("valid cron is returned untouched", () => {
78
+ const VALID: Array<string> = [
79
+ "* * * * *",
80
+ "*/2 * * * *",
81
+ "*/5 * * * *",
82
+ "*/10 * * * *",
83
+ "*/15 * * * *",
84
+ "*/30 * * * *",
85
+ "0 * * * *",
86
+ "0 */6 * * *",
87
+ "0 0 * * *",
88
+ "0 0 * * 0",
89
+ "0 9 * * 1",
90
+ "3-59/5 * * * *",
91
+ "0,15,30,45 * * * *",
92
+ ];
93
+
94
+ test.each(VALID)("%j passes through byte-identical", (cron: string) => {
95
+ const result: MonitoringIntervalNormalization =
96
+ MonitoringIntervalUtil.normalize(cron);
97
+
98
+ expect(result.status).toBe(
99
+ MonitoringIntervalNormalizationStatus.AlreadyCanonical,
100
+ );
101
+ expect(result.cron).toBe(cron);
102
+ });
103
+
104
+ test("cron-parser shortcuts are never REWRITTEN into something else", () => {
105
+ /*
106
+ * "@hourly" is a deliberate seam between the two parsers. The
107
+ * isomorphic validator here is a hand-rolled 5-field check and does
108
+ * not know it; cron-parser, which actually schedules the probe, does.
109
+ *
110
+ * What matters is that this util never GUESSES: it reports
111
+ * Unrecognized with a null cron rather than rewriting "@hourly" into
112
+ * "0 * * * *". The server validator's cron-parser fallback is what
113
+ * accepts it on write, and resolveNextPingAt's raw-parse-first order
114
+ * is what honours it at runtime — both covered in their own suites.
115
+ * If this util ever started rewriting it, a stored value would change
116
+ * under the customer for no behavioural gain.
117
+ */
118
+ const result: MonitoringIntervalNormalization =
119
+ MonitoringIntervalUtil.normalize("@hourly");
120
+
121
+ expect(result.status).toBe(
122
+ MonitoringIntervalNormalizationStatus.Unrecognized,
123
+ );
124
+ expect(result.cron).toBeNull();
125
+ });
126
+ });
127
+
128
+ describe("empty is a legitimate state, never an error", () => {
129
+ /*
130
+ * ~4,177 production rows are NULL or blank. A Manual monitor is never
131
+ * probed; treating that as invalid would break every one of them.
132
+ */
133
+ test.each([null, undefined, "", " ", "\t\n"])(
134
+ "%j is Empty with a null cron",
135
+ (value: string | null | undefined) => {
136
+ const result: MonitoringIntervalNormalization =
137
+ MonitoringIntervalUtil.normalize(value);
138
+
139
+ expect(result.status).toBe(MonitoringIntervalNormalizationStatus.Empty);
140
+ expect(result.cron).toBeNull();
141
+ },
142
+ );
143
+ });
144
+
145
+ describe("label tolerance", () => {
146
+ test("is case-insensitive", () => {
147
+ expect(normalize("EVERY 5 MINUTES")).toBe("*/5 * * * *");
148
+ expect(normalize("every 5 minutes")).toBe("*/5 * * * *");
149
+ expect(normalize("Every 5 Minutes")).toBe("*/5 * * * *");
150
+ });
151
+
152
+ test("collapses runs of whitespace, including a non-breaking space", () => {
153
+ expect(normalize("Every 5 minutes")).toBe("*/5 * * * *");
154
+ expect(normalize(" Every 5 minutes ")).toBe("*/5 * * * *");
155
+ // U+00A0 survives a copy-paste out of rendered docs.
156
+ expect(normalize("Every 5 minutes")).toBe("*/5 * * * *");
157
+ });
158
+
159
+ test("strips wrapping quotes and a trailing period", () => {
160
+ expect(normalize('"Every 5 minutes"')).toBe("*/5 * * * *");
161
+ expect(normalize("'5m'")).toBe("*/5 * * * *");
162
+ expect(normalize("Every 5 minutes.")).toBe("*/5 * * * *");
163
+ });
164
+
165
+ test("reads hyphenated and underscored forms", () => {
166
+ expect(normalize("every-1-min")).toBe("* * * * *");
167
+ expect(normalize("every_5_minutes")).toBe("*/5 * * * *");
168
+ });
169
+
170
+ test("covers every label the shared preset list offers", () => {
171
+ /*
172
+ * The table is built by iterating CronTab.PRESETS, so a preset added
173
+ * there is understood here without anyone editing the util. This
174
+ * asserts that wiring rather than the individual labels.
175
+ */
176
+ for (const preset of CronTab.PRESETS) {
177
+ expect(normalize(preset.label)).toBe(preset.value);
178
+ }
179
+ });
180
+ });
181
+
182
+ describe("duration grammar", () => {
183
+ test.each([
184
+ ["1m", "* * * * *"],
185
+ ["1 min", "* * * * *"],
186
+ ["minutely", "* * * * *"],
187
+ ["2m", "*/2 * * * *"],
188
+ ["10 mins", "*/10 * * * *"],
189
+ ["15 minutes", "*/15 * * * *"],
190
+ ["30m", "*/30 * * * *"],
191
+ ["60m", "0 * * * *"],
192
+ ["1h", "0 * * * *"],
193
+ ["hourly", "0 * * * *"],
194
+ ["2 hours", "0 */2 * * *"],
195
+ ["6h", "0 */6 * * *"],
196
+ ["12 hrs", "0 */12 * * *"],
197
+ ["24h", "0 0 * * *"],
198
+ ["1d", "0 0 * * *"],
199
+ ["daily", "0 0 * * *"],
200
+ ["1 week", "0 0 * * 0"],
201
+ ["weekly", "0 0 * * 0"],
202
+ ])("reads %j as %j", (input: string, expected: string) => {
203
+ expect(normalize(input)).toBe(expected);
204
+ });
205
+ });
206
+
207
+ describe("refuses to store a lie", () => {
208
+ /*
209
+ * "*_/7 * * * *" fires at :00, :07 ... :56 and then :00 — a four-minute
210
+ * gap at every hour wrap. It is NOT "every 7 minutes", so normalizing
211
+ * "every 7 minutes" to it would store something false. Better to refuse
212
+ * and let the caller write the cron they actually mean.
213
+ */
214
+ test.each([
215
+ "7m",
216
+ "every 7 minutes",
217
+ "13 minutes",
218
+ "5 hours",
219
+ "7h",
220
+ "2 days",
221
+ "3 weeks",
222
+ ])(
223
+ "%j is Unrecognized rather than silently approximated",
224
+ (input: string) => {
225
+ const result: MonitoringIntervalNormalization =
226
+ MonitoringIntervalUtil.normalize(input);
227
+
228
+ expect(result.status).toBe(
229
+ MonitoringIntervalNormalizationStatus.Unrecognized,
230
+ );
231
+ expect(result.cron).toBeNull();
232
+ },
233
+ );
234
+
235
+ test("sub-minute cadences are not invented", () => {
236
+ /*
237
+ * The claim loop ticks once a minute, so a per-second cadence is a
238
+ * promise the probe fleet cannot keep.
239
+ */
240
+ for (const input of ["30s", "1s", "10 seconds", "1 sec"]) {
241
+ expect(normalize(input)).toBeNull();
242
+ }
243
+ });
244
+ });
245
+
246
+ describe("genuine nonsense stays Unrecognized", () => {
247
+ test.each([
248
+ "banana",
249
+ "asap",
250
+ "not a cron",
251
+ "soon",
252
+ "-1m",
253
+ "0m",
254
+ "every",
255
+ "minutes",
256
+ ])("%j", (input: string) => {
257
+ expect(normalize(input)).toBeNull();
258
+ });
259
+ });
260
+
261
+ describe("totality", () => {
262
+ /*
263
+ * It runs in a write hook, on the scheduler hot path and inside a
264
+ * migration. A throw in any of those is worse than a null.
265
+ */
266
+ test("never throws, whatever it is handed", () => {
267
+ const hostile: Array<unknown> = [
268
+ null,
269
+ undefined,
270
+ "",
271
+ "🙂",
272
+ "*".repeat(5000),
273
+ "{{ variable }}",
274
+ "; DROP TABLE Monitor; --",
275
+ "",
276
+ 12345,
277
+ {},
278
+ [],
279
+ ];
280
+
281
+ for (const value of hostile) {
282
+ expect(() => {
283
+ return MonitoringIntervalUtil.normalize(value as string);
284
+ }).not.toThrow();
285
+ }
286
+ });
287
+
288
+ test("is idempotent — normalizing its own output changes nothing", () => {
289
+ const inputs: Array<string> = [
290
+ "5m",
291
+ "Every 5 minutes",
292
+ "1 day",
293
+ "every-1-min",
294
+ "*/5 * * * *",
295
+ ];
296
+
297
+ for (const input of inputs) {
298
+ const once: string | null = normalize(input);
299
+ expect(once).not.toBeNull();
300
+ expect(normalize(once)).toBe(once);
301
+ }
302
+ });
303
+ });
304
+ });
@@ -4,8 +4,6 @@ import {
4
4
  formatErrorBudgetRemainingOfTotal,
5
5
  } from "../../../Utils/Slo/SloDuration";
6
6
 
7
- const MINUS_SIGN: string = "−";
8
-
9
7
  describe("SloDuration", () => {
10
8
  describe("formatDurationCompact", () => {
11
9
  it("renders seconds under a minute", () => {
@@ -74,12 +72,38 @@ describe("SloDuration", () => {
74
72
 
75
73
  it("renders an exhausted-but-not-overspent budget as 0s left", () => {
76
74
  expect(formatErrorBudgetRemaining(0)).toBe("0s left");
75
+ expect(formatErrorBudgetRemaining(-0)).toBe("0s left");
76
+ });
77
+
78
+ it("states the overage as a positive duration with over budget", () => {
79
+ expect(formatErrorBudgetRemaining(-750)).toBe("12m 30s over budget");
77
80
  });
78
81
 
79
- it("renders an overspent budget with a minus sign and over budget", () => {
80
- expect(formatErrorBudgetRemaining(-750)).toBe(
81
- `${MINUS_SIGN}12m 30s over budget`,
82
- );
82
+ it("keeps a multi-day overage readable", () => {
83
+ expect(formatErrorBudgetRemaining(-346980)).toBe("4d 23m over budget");
84
+ });
85
+
86
+ it.each([0.001, 0.4, 0.999])(
87
+ "distinguishes a positive %ps remainder from an empty budget",
88
+ (seconds: number) => {
89
+ expect(formatErrorBudgetRemaining(seconds)).toBe("under 1s left");
90
+ },
91
+ );
92
+
93
+ it.each([-0.001, -0.4, -0.999])(
94
+ "preserves a %ps overage instead of rounding it to zero",
95
+ (seconds: number) => {
96
+ expect(formatErrorBudgetRemaining(seconds)).toBe(
97
+ "under 1s over budget",
98
+ );
99
+ },
100
+ );
101
+
102
+ it("uses seconds at the one-second boundary without rounding up", () => {
103
+ expect(formatErrorBudgetRemaining(1)).toBe("1s left");
104
+ expect(formatErrorBudgetRemaining(-1)).toBe("1s over budget");
105
+ expect(formatErrorBudgetRemaining(59.9)).toBe("59s left");
106
+ expect(formatErrorBudgetRemaining(-59.9)).toBe("59s over budget");
83
107
  });
84
108
 
85
109
  it("returns null when the SLO has not been evaluated", () => {
@@ -90,6 +114,7 @@ describe("SloDuration", () => {
90
114
  it("returns null for non-finite values", () => {
91
115
  expect(formatErrorBudgetRemaining(Number.NaN)).toBeNull();
92
116
  expect(formatErrorBudgetRemaining(Number.POSITIVE_INFINITY)).toBeNull();
117
+ expect(formatErrorBudgetRemaining(Number.NEGATIVE_INFINITY)).toBeNull();
93
118
  });
94
119
 
95
120
  it("rejects a numeric string rather than coercing it", () => {
@@ -97,6 +122,11 @@ describe("SloDuration", () => {
97
122
  formatErrorBudgetRemaining("2592" as unknown as number),
98
123
  ).toBeNull();
99
124
  });
125
+
126
+ it("rejects booleans rather than treating them as zero or one", () => {
127
+ expect(formatErrorBudgetRemaining(false as unknown as number)).toBeNull();
128
+ expect(formatErrorBudgetRemaining(true as unknown as number)).toBeNull();
129
+ });
100
130
  });
101
131
 
102
132
  describe("formatErrorBudgetRemainingOfTotal", () => {
@@ -109,40 +139,101 @@ describe("SloDuration", () => {
109
139
  ).toBe("12m 30s left of 43m 12s");
110
140
  });
111
141
 
112
- it("keeps the total visible when the budget is overspent", () => {
142
+ it("identifies the allowance separately from how far over budget it is", () => {
113
143
  expect(
114
144
  formatErrorBudgetRemainingOfTotal({
115
145
  remainingSeconds: -750,
116
146
  totalSeconds: 2592,
117
147
  }),
118
- ).toBe(`${MINUS_SIGN}12m 30s over budget of 43m 12s`);
148
+ ).toBe("12m 30s over budget · 43m 12s allowed");
119
149
  });
120
150
 
121
- it("omits the total when it is unknown", () => {
151
+ it("explains the reported multi-day overage against its small allowance", () => {
122
152
  expect(
123
153
  formatErrorBudgetRemainingOfTotal({
124
- remainingSeconds: 750,
125
- totalSeconds: null,
154
+ remainingSeconds: -346980,
155
+ totalSeconds: 347,
126
156
  }),
127
- ).toBe("12m 30s left");
157
+ ).toBe("4d 23m over budget · 5m 47s allowed");
128
158
  });
129
159
 
130
- it("omits a zero total — a brand-new SLO has no elapsed window yet", () => {
160
+ it("retains the allowance at exactly zero without claiming an overage", () => {
131
161
  expect(
132
162
  formatErrorBudgetRemainingOfTotal({
133
163
  remainingSeconds: 0,
134
- totalSeconds: 0,
135
- }),
136
- ).toBe("0s left");
137
- });
138
-
139
- it("returns null when the SLO has not been evaluated", () => {
140
- expect(
141
- formatErrorBudgetRemainingOfTotal({
142
- remainingSeconds: null,
143
164
  totalSeconds: 2592,
144
165
  }),
145
- ).toBeNull();
146
- });
166
+ ).toBe("0s left of 43m 12s");
167
+ });
168
+
169
+ it.each([
170
+ [0.25, "under 1s left of under 1s"],
171
+ [-0.25, "under 1s over budget · under 1s allowed"],
172
+ [0, "0s left of under 1s"],
173
+ ])(
174
+ "does not round a subsecond allowance to zero for a %ps remainder",
175
+ (remainingSeconds: number, expected: string) => {
176
+ expect(
177
+ formatErrorBudgetRemainingOfTotal({
178
+ remainingSeconds,
179
+ totalSeconds: 0.5,
180
+ }),
181
+ ).toBe(expected);
182
+ },
183
+ );
184
+
185
+ it.each([
186
+ ["missing", undefined],
187
+ ["null", null],
188
+ ["zero", 0],
189
+ ["negative", -2592],
190
+ ["NaN", Number.NaN],
191
+ ["positive infinity", Number.POSITIVE_INFINITY],
192
+ ["negative infinity", Number.NEGATIVE_INFINITY],
193
+ ["numeric string", "2592" as unknown as number],
194
+ ["boolean", true as unknown as number],
195
+ ])(
196
+ "omits an unusable %s total while preserving the remaining or over-budget state",
197
+ (_label: string, totalSeconds: number | null | undefined) => {
198
+ expect(
199
+ formatErrorBudgetRemainingOfTotal({
200
+ remainingSeconds: 750,
201
+ totalSeconds,
202
+ }),
203
+ ).toBe("12m 30s left");
204
+ expect(
205
+ formatErrorBudgetRemainingOfTotal({
206
+ remainingSeconds: -750,
207
+ totalSeconds,
208
+ }),
209
+ ).toBe("12m 30s over budget");
210
+ expect(
211
+ formatErrorBudgetRemainingOfTotal({
212
+ remainingSeconds: 0,
213
+ totalSeconds,
214
+ }),
215
+ ).toBe("0s left");
216
+ },
217
+ );
218
+
219
+ it.each([
220
+ ["missing", undefined],
221
+ ["null", null],
222
+ ["NaN", Number.NaN],
223
+ ["positive infinity", Number.POSITIVE_INFINITY],
224
+ ["negative infinity", Number.NEGATIVE_INFINITY],
225
+ ["numeric string", "750" as unknown as number],
226
+ ["boolean", false as unknown as number],
227
+ ])(
228
+ "does not let a known total imply an evaluated budget when the remainder is %s",
229
+ (_label: string, remainingSeconds: number | null | undefined) => {
230
+ expect(
231
+ formatErrorBudgetRemainingOfTotal({
232
+ remainingSeconds,
233
+ totalSeconds: 2592,
234
+ }),
235
+ ).toBeNull();
236
+ },
237
+ );
147
238
  });
148
239
  });
@@ -58,7 +58,7 @@ const EVERY_NOTICE_INPUT: Array<{ name: string; data: SloNoticeData }> = [
58
58
  },
59
59
  },
60
60
  {
61
- name: "generic misconfigured",
61
+ name: "waiting for evaluation with monitors attached",
62
62
  data: { ...MEASURING, sloStatus: SloStatus.Misconfigured },
63
63
  },
64
64
  { name: "paused", data: { ...MEASURING, sloStatus: SloStatus.Paused } },
@@ -431,17 +431,100 @@ describe("SloHealth", () => {
431
431
  expect(notice?.body).toContain(SliType.MonitorUptime);
432
432
  });
433
433
 
434
- it("falls back to a generic reason for Misconfigured", () => {
435
- const notice: SloNotice | null = getSloNotice({
436
- isEnabled: true,
437
- sloStatus: SloStatus.Misconfigured,
438
- sliType: SliType.MonitorUptime,
439
- monitorCount: 1,
440
- targetPercentage: 99.9,
441
- lastEvaluatedAt: new Date(),
434
+ describe("waiting for evaluation after monitors are attached", () => {
435
+ it.each([
436
+ { monitorCount: 1, lastEvaluatedAt: null },
437
+ { monitorCount: 16, lastEvaluatedAt: null },
438
+ { monitorCount: 1, lastEvaluatedAt: undefined },
439
+ { monitorCount: 16, lastEvaluatedAt: undefined },
440
+ {
441
+ monitorCount: 1,
442
+ lastEvaluatedAt: new Date("2026-09-21T12:00:00.000Z"),
443
+ },
444
+ {
445
+ monitorCount: 16,
446
+ lastEvaluatedAt: "2026-09-21T12:00:00.000Z",
447
+ },
448
+ ])(
449
+ "is informational with $monitorCount monitors and lastEvaluatedAt=$lastEvaluatedAt",
450
+ ({
451
+ monitorCount,
452
+ lastEvaluatedAt,
453
+ }: {
454
+ monitorCount: number;
455
+ lastEvaluatedAt: Date | string | null | undefined;
456
+ }) => {
457
+ const notice: SloNotice | null = getSloNotice({
458
+ ...MEASURING,
459
+ sloStatus: SloStatus.Misconfigured,
460
+ monitorCount,
461
+ lastEvaluatedAt,
462
+ });
463
+
464
+ expect(notice?.type).toBe(SloNoticeType.Info);
465
+ expect(notice?.title).toBe("Waiting for SLO evaluation");
466
+ expect(notice?.body).toContain("Monitors are attached");
467
+ expect(notice?.body).toContain("every few minutes");
468
+ expect(notice?.body).toContain(
469
+ "once monitor status data is available and the next evaluation completes",
470
+ );
471
+ expect(notice?.action).toEqual({
472
+ label: "View monitors",
473
+ target: SloNoticeActionTarget.Monitors,
474
+ });
475
+ },
476
+ );
477
+
478
+ it.each([undefined, null])(
479
+ "retains the default monitor-uptime behavior when sliType is %s",
480
+ (sliType: undefined | null) => {
481
+ expect(
482
+ getSloNotice({
483
+ ...MEASURING,
484
+ sloStatus: SloStatus.Misconfigured,
485
+ sliType,
486
+ })?.type,
487
+ ).toBe(SloNoticeType.Info);
488
+ },
489
+ );
490
+
491
+ it.each([0, -1, 100, 101, Number.NaN, Infinity, null, undefined])(
492
+ "still warns about target %s even with monitors attached",
493
+ (targetPercentage: number | null | undefined) => {
494
+ const notice: SloNotice | null = getSloNotice({
495
+ ...MEASURING,
496
+ sloStatus: SloStatus.Misconfigured,
497
+ monitorCount: 16,
498
+ targetPercentage,
499
+ });
500
+
501
+ expect(notice?.type).toBe(SloNoticeType.Warning);
502
+ expect(notice?.title).toBe("The target is out of range");
503
+ expect(notice?.action?.target).toBe(SloNoticeActionTarget.Settings);
504
+ },
505
+ );
506
+
507
+ it("still warns about an unsupported SLI with monitors attached", () => {
508
+ const notice: SloNotice | null = getSloNotice({
509
+ ...MEASURING,
510
+ sloStatus: SloStatus.Misconfigured,
511
+ sliType: SliType.Metric,
512
+ monitorCount: 16,
513
+ });
514
+
515
+ expect(notice?.type).toBe(SloNoticeType.Warning);
516
+ expect(notice?.title).toBe("This SLO cannot be evaluated");
517
+ expect(notice?.action).toBeUndefined();
442
518
  });
443
519
 
444
- expect(notice?.title).toBe("This SLO cannot be evaluated");
520
+ it.each([SloStatus.Healthy, SloStatus.AtRisk, SloStatus.BudgetExhausted])(
521
+ "stops displaying the notice after evaluation reports %s",
522
+ (sloStatus: SloStatus) => {
523
+ expect(
524
+ getSloNotice({ ...MEASURING, sloStatus, monitorCount: 16 }),
525
+ ).toBeNull();
526
+ },
527
+ );
445
528
  });
446
529
 
447
530
  it("explains Paused", () => {