@oneuptime/common 13.0.8 → 14.0.0

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 (333) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Monitor.ts +3 -2
  4. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  5. package/Scripts/generate-service-worker.js +65 -4
  6. package/Server/API/BaseAPI.ts +26 -5
  7. package/Server/API/GlobalConfigAPI.ts +228 -462
  8. package/Server/API/ProjectOIDC.ts +25 -16
  9. package/Server/API/ProjectSSO.ts +24 -16
  10. package/Server/API/StatusPageAPI.ts +100 -42
  11. package/Server/API/TeamMemberAPI.ts +10 -1
  12. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  13. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  14. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  15. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  16. package/Server/EnvironmentConfig.ts +147 -2
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  19. package/Server/Middleware/UserAuthorization.ts +38 -16
  20. package/Server/Services/AuditLogService.ts +84 -1079
  21. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  22. package/Server/Services/GlobalConfigService.ts +80 -1
  23. package/Server/Services/MonitorProbeService.ts +116 -20
  24. package/Server/Services/MonitorService.ts +56 -4
  25. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  26. package/Server/Services/MonitorTemplateService.ts +26 -0
  27. package/Server/Services/ProjectService.ts +284 -0
  28. package/Server/Services/RumSessionPinService.ts +25 -6
  29. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  30. package/Server/Services/StatusPageService.ts +78 -1
  31. package/Server/Services/TeamMemberService.ts +11 -0
  32. package/Server/Services/TeamService.ts +10 -0
  33. package/Server/Services/UserService.ts +10 -17
  34. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  35. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  36. package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
  37. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  38. package/Server/Types/Markdown.ts +41 -0
  39. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  40. package/Server/Utils/EditionEnforcement.ts +233 -0
  41. package/Server/Utils/FrontendEnvironment.ts +41 -2
  42. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  43. package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
  44. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  45. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
  46. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  47. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  48. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  49. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  50. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  51. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  52. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  53. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  54. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  55. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  56. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  57. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  58. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  59. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  60. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
  61. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  62. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  63. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
  64. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  65. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  66. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  67. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  68. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  69. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  70. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  71. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  72. package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
  73. package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
  74. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  75. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  76. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  77. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  78. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  79. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  80. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  81. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  82. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  83. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  84. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  85. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  86. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  87. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  88. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  89. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  90. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  91. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  92. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  93. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  94. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  95. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  96. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  97. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  98. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  99. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  100. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  101. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  102. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  103. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  104. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  105. package/Tests/Server/Types/Markdown.test.ts +181 -0
  106. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  107. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  108. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  109. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  110. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  111. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  112. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
  113. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  114. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  115. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  116. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  117. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  118. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  119. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  120. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
  121. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  122. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  123. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  124. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  125. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  126. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  127. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  128. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  129. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  130. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  131. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  132. package/Types/API/Hostname.ts +63 -16
  133. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  134. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  135. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  136. package/Types/Database/CanonicalModelInstance.ts +102 -0
  137. package/Types/Database/TableColumn.ts +20 -6
  138. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  139. package/Types/IP/IPv6.ts +6 -1
  140. package/Types/Monitor/MonitorStep.ts +6 -1
  141. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  142. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  143. package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
  144. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  145. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  146. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  147. package/UI/Components/ModelList/ModelList.tsx +11 -1
  148. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  149. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  150. package/UI/esbuild-enterprise.js +263 -0
  151. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  152. package/Utils/HostAddressUtil.ts +94 -0
  153. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  154. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  155. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  156. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  157. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  158. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  159. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  160. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  161. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  162. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  163. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  164. package/build/dist/Server/API/BaseAPI.js +26 -5
  165. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  166. package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
  167. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  168. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  169. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  170. package/build/dist/Server/API/ProjectSSO.js +24 -16
  171. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  172. package/build/dist/Server/API/StatusPageAPI.js +93 -43
  173. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  174. package/build/dist/Server/API/TeamMemberAPI.js +8 -1
  175. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  176. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  177. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  178. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  179. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  180. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  181. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  182. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  183. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  184. package/build/dist/Server/EnvironmentConfig.js +84 -2
  185. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  190. package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
  191. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  192. package/build/dist/Server/Services/AuditLogService.js +71 -740
  193. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  194. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  195. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  196. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  197. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  198. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  199. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  200. package/build/dist/Server/Services/MonitorService.js +45 -4
  201. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  202. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  203. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  204. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  205. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  206. package/build/dist/Server/Services/ProjectService.js +214 -0
  207. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  208. package/build/dist/Server/Services/RumSessionPinService.js +24 -6
  209. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  210. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  211. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  212. package/build/dist/Server/Services/StatusPageService.js +71 -0
  213. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  214. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  215. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  216. package/build/dist/Server/Services/TeamService.js +9 -0
  217. package/build/dist/Server/Services/TeamService.js.map +1 -1
  218. package/build/dist/Server/Services/UserService.js +10 -16
  219. package/build/dist/Server/Services/UserService.js.map +1 -1
  220. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  221. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  222. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  223. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  224. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
  225. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  226. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  227. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  228. package/build/dist/Server/Types/Markdown.js +31 -0
  229. package/build/dist/Server/Types/Markdown.js.map +1 -1
  230. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  231. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  232. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  233. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  234. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  235. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  236. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  237. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  238. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
  239. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  240. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  241. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  242. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
  243. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  245. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  246. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  247. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  248. package/build/dist/Types/API/Hostname.js +59 -11
  249. package/build/dist/Types/API/Hostname.js.map +1 -1
  250. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  251. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  252. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  253. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  254. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  255. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  256. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  257. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  258. package/build/dist/Types/Database/TableColumn.js +19 -6
  259. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  260. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  261. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  262. package/build/dist/Types/IP/IPv6.js +6 -1
  263. package/build/dist/Types/IP/IPv6.js.map +1 -1
  264. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  265. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  266. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  267. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  268. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  269. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
  270. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  271. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  272. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  273. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  274. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  275. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  276. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  277. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  278. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  279. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  280. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  281. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  282. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  283. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  284. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  285. package/build/dist/Utils/HostAddressUtil.js +80 -0
  286. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  287. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  288. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  289. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  290. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  291. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  292. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  293. package/jest.config.json +3 -1
  294. package/package.json +1 -1
  295. package/test-setup.sh +103 -34
  296. package/tsconfig.json +13 -0
  297. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  298. package/Server/API/TeamComplianceAPI.ts +0 -158
  299. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  300. package/Server/Services/TeamComplianceService.ts +0 -733
  301. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  302. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  303. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  304. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  305. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
  306. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  307. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  308. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
  309. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  310. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  311. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  312. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  313. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  314. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  315. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  316. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  317. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  318. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  319. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  320. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  321. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  322. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  323. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  324. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  325. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  326. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  327. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  328. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  329. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  330. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  331. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  332. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  333. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
2
2
  import { ColumnAccessControl } from "../../BaseDatabase/AccessControl";
3
+ import getCanonicalModelInstance from "../CanonicalModelInstance";
3
4
  import Dictionary from "../../Dictionary";
4
5
  import { ReflectionMetadataType } from "../../Reflection";
5
6
  import "reflect-metadata";
@@ -31,10 +32,12 @@ type GetColumnAccessControlForAllColumnsFunction = <T extends BaseModel>(
31
32
  ) => Dictionary<ColumnAccessControl>;
32
33
 
33
34
  /*
34
- * Per-class cache. Safe to key on the constructor because every decorated
35
- * column is initialised to `undefined` in the class body, so Object.keys()
36
- * is identical for every instance of a class (see OwnerOnlyColumn.ts).
37
- * Callers must treat the returned dictionary as read-only.
35
+ * Per-class cache, keyed on the constructor and built from a canonical
36
+ * instance of that class rather than from whichever instance asked first, so
37
+ * a caller that has deleted a column off its own instance cannot define what
38
+ * the class reports for the rest of the process. See
39
+ * CanonicalModelInstance.ts for the bug this prevents. Callers must treat the
40
+ * returned dictionary as read-only.
38
41
  */
39
42
  const accessControlCache: WeakMap<
40
43
  { new (): BaseModel },
@@ -50,12 +53,14 @@ export const getColumnAccessControlForAllColumns: GetColumnAccessControlForAllCo
50
53
  accessControlCache.get(modelClass);
51
54
 
52
55
  if (!cached) {
56
+ const canonical: T | null = getCanonicalModelInstance(target);
57
+ const metadataSource: T = canonical || target;
53
58
  const dictonary: Dictionary<ColumnAccessControl> = {};
54
- const keys: Array<string> = Object.keys(target);
59
+ const keys: Array<string> = Object.keys(metadataSource);
55
60
 
56
61
  for (const key of keys) {
57
62
  const accessControl: ColumnAccessControl | undefined =
58
- Reflect.getMetadata(accessControlSymbol, target, key) as
63
+ Reflect.getMetadata(accessControlSymbol, metadataSource, key) as
59
64
  | ColumnAccessControl
60
65
  | undefined;
61
66
  if (accessControl) {
@@ -64,7 +69,14 @@ export const getColumnAccessControlForAllColumns: GetColumnAccessControlForAllCo
64
69
  }
65
70
 
66
71
  cached = dictonary;
67
- accessControlCache.set(modelClass, cached);
72
+ /*
73
+ * No canonical instance (see CanonicalModelInstance): answer from the
74
+ * instance we were handed, but do NOT cache it for the class - that
75
+ * instance may be a mutilated one, and a cached answer outlives it.
76
+ */
77
+ if (canonical) {
78
+ accessControlCache.set(modelClass, cached);
79
+ }
68
80
  }
69
81
 
70
82
  return cached;
@@ -1,5 +1,6 @@
1
1
  import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
2
2
  import ColumnBillingAccessControl from "../../BaseDatabase/ColumnBillingAccessControl";
3
+ import getCanonicalModelInstance from "../CanonicalModelInstance";
3
4
  import Dictionary from "../../Dictionary";
4
5
  import { ReflectionMetadataType } from "../../Reflection";
5
6
  import "reflect-metadata";
@@ -31,10 +32,12 @@ type GetColumnBillingAccessControlForAllColumnsFunction = <T extends BaseModel>(
31
32
  ) => Dictionary<ColumnBillingAccessControl>;
32
33
 
33
34
  /*
34
- * Per-class cache. Safe to key on the constructor because every decorated
35
- * column is initialised to `undefined` in the class body, so Object.keys()
36
- * is identical for every instance of a class (see OwnerOnlyColumn.ts).
37
- * Callers must treat the returned dictionary as read-only.
35
+ * Per-class cache, keyed on the constructor and built from a canonical
36
+ * instance of that class rather than from whichever instance asked first, so
37
+ * a caller that has deleted a column off its own instance cannot define what
38
+ * the class reports for the rest of the process. See
39
+ * CanonicalModelInstance.ts for the bug this prevents. Callers must treat the
40
+ * returned dictionary as read-only.
38
41
  */
39
42
  const billingAccessControlCache: WeakMap<
40
43
  { new (): BaseModel },
@@ -50,12 +53,14 @@ export const getColumnBillingAccessControlForAllColumns: GetColumnBillingAccessC
50
53
  billingAccessControlCache.get(modelClass);
51
54
 
52
55
  if (!cached) {
56
+ const canonical: T | null = getCanonicalModelInstance(target);
57
+ const metadataSource: T = canonical || target;
53
58
  const dictonary: Dictionary<ColumnBillingAccessControl> = {};
54
- const keys: Array<string> = Object.keys(target);
59
+ const keys: Array<string> = Object.keys(metadataSource);
55
60
 
56
61
  for (const key of keys) {
57
62
  const accessControl: ColumnBillingAccessControl | undefined =
58
- Reflect.getMetadata(accessControlSymbol, target, key) as
63
+ Reflect.getMetadata(accessControlSymbol, metadataSource, key) as
59
64
  | ColumnBillingAccessControl
60
65
  | undefined;
61
66
  if (accessControl) {
@@ -64,7 +69,14 @@ export const getColumnBillingAccessControlForAllColumns: GetColumnBillingAccessC
64
69
  }
65
70
 
66
71
  cached = dictonary;
67
- billingAccessControlCache.set(modelClass, cached);
72
+ /*
73
+ * No canonical instance (see CanonicalModelInstance): answer from the
74
+ * instance we were handed, but do NOT cache it for the class - that
75
+ * instance may be a mutilated one, and a cached answer outlives it.
76
+ */
77
+ if (canonical) {
78
+ billingAccessControlCache.set(modelClass, cached);
79
+ }
68
80
  }
69
81
 
70
82
  return cached;
@@ -1,4 +1,5 @@
1
1
  import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
2
+ import getCanonicalModelInstance from "../CanonicalModelInstance";
2
3
  import { ReflectionMetadataType } from "../../Reflection";
3
4
  import "reflect-metadata";
4
5
 
@@ -66,10 +67,14 @@ type GetOwnerOnlyColumnsFunction = <T extends BaseModel>(
66
67
  ) => Array<string>;
67
68
 
68
69
  /**
69
- * Every owner-only column on this model. Enumerating requires the property to
70
- * exist on the instance, which it does for every declared column because model
71
- * columns are initialised to `undefined` in the class body - the same
72
- * assumption getTableColumns() already makes.
70
+ * Every owner-only column on this model. Which columns a MODEL marks is a
71
+ * property of the class, so the enumeration reads a canonical instance of the
72
+ * class rather than the caller's own instance: a caller that had deleted a
73
+ * key off its instance would otherwise get an answer that silently omits a
74
+ * marked column, and this list is what OwnerOnlyColumnPermission enforces
75
+ * against. See CanonicalModelInstance.ts. (Enumerating at all relies on every
76
+ * declared column being initialised to `undefined` in the class body - the
77
+ * same assumption getTableColumns() makes.)
73
78
  */
74
79
  export const getOwnerOnlyColumns: GetOwnerOnlyColumnsFunction = <
75
80
  T extends BaseModel,
@@ -77,9 +82,13 @@ export const getOwnerOnlyColumns: GetOwnerOnlyColumnsFunction = <
77
82
  target: T,
78
83
  ): Array<string> => {
79
84
  const columns: Array<string> = [];
85
+ // Nothing is cached here, so falling back to the caller's instance is safe.
86
+ const metadataSource: T = getCanonicalModelInstance(target) || target;
80
87
 
81
- for (const key of Object.keys(target)) {
82
- if (Reflect.getMetadata(ownerOnlyColumnSymbol, target, key) === true) {
88
+ for (const key of Object.keys(metadataSource)) {
89
+ if (
90
+ Reflect.getMetadata(ownerOnlyColumnSymbol, metadataSource, key) === true
91
+ ) {
83
92
  columns.push(key);
84
93
  }
85
94
  }
@@ -0,0 +1,102 @@
1
+ /*
2
+ * The one instance of a model class that column-metadata enumeration is
3
+ * allowed to look at.
4
+ *
5
+ * WHY THIS EXISTS.
6
+ *
7
+ * Every "which columns does this model have" lookup in this directory answers
8
+ * the question by enumerating an INSTANCE's own keys (Object.keys) and then
9
+ * caching the answer per CLASS. That is only sound while every instance of a
10
+ * class has the same own keys. The class bodies do guarantee that - each
11
+ * decorated column is initialised to `undefined` - right up until some caller
12
+ * deletes a key off a live instance.
13
+ *
14
+ * One caller did. BaseAPI.createItem used to `delete item._id` before handing
15
+ * the model to the service, and DatabaseService.create asks that very instance
16
+ * for its columns (generateDefaultValues). Whenever the mutilated instance was
17
+ * the first to ask, the class's cached column list was built WITHOUT `_id` -
18
+ * permanently, for the life of the process, for every later caller - and since
19
+ * DatabaseBaseModel.toJSONObject serialises a row by iterating exactly that
20
+ * list, every API response for that model silently lost its id. A single
21
+ * create was enough, including a create that was refused, because the columns
22
+ * are read before the permission check. Rows still carried their real `_id` in
23
+ * memory and in the SQL projection; it was dropped on the way out.
24
+ *
25
+ * So enumeration stopped reading the caller's instance. It reads a frozen,
26
+ * private instance of the caller's CLASS instead - constructed here, reachable
27
+ * by nobody, impossible to mutate - so what a class reports about itself can
28
+ * never depend on which instance happened to ask first, or on what anyone did
29
+ * to that instance. Reads already constructed a throwaway instance for exactly
30
+ * this purpose (SelectPermission, QueryPermission, ColumnPermission all do
31
+ * `new modelType()`), which is why a single read of a model was enough to make
32
+ * the same create harmless; this makes that the only behaviour.
33
+ *
34
+ * Every database model is no-arg constructible (Models/DatabaseModels/Index.ts
35
+ * relies on it already, in getModelTypeByName), and a fresh instance carries
36
+ * every declared column - both facts are asserted by
37
+ * Tests/Types/Database/CanonicalModelInstance.test.ts against all 400+ models.
38
+ */
39
+
40
+ type NoArgConstructor = new () => unknown;
41
+
42
+ const canonicalInstanceCache: WeakMap<NoArgConstructor, unknown> =
43
+ new WeakMap();
44
+
45
+ /*
46
+ * Classes whose canonical instance is being constructed right now. A model
47
+ * constructor that asked for its own columns would otherwise recurse forever;
48
+ * such a call gets the caller's instance instead, which is the old behaviour.
49
+ */
50
+ const beingConstructed: WeakSet<NoArgConstructor> = new WeakSet();
51
+
52
+ /**
53
+ * A frozen, shared instance of `target`'s class, safe to enumerate for
54
+ * metadata - or NULL when no such instance can be made: a class that needs
55
+ * constructor arguments, a class still being defined (circular imports), a
56
+ * constructor that throws, or a plain object with no useful constructor.
57
+ *
58
+ * Null, rather than falling back to `target`, because the two are NOT
59
+ * interchangeable and treating them as if they were is how this bug worked in
60
+ * the first place. A caller with no canonical instance may still answer from
61
+ * whatever instance it was handed - a metadata lookup must never be the reason
62
+ * a process fails to boot - but it must not then CACHE that answer for the
63
+ * class, because the instance it read may be a mutilated one and the cached
64
+ * answer would outlive it. Returning null forces each caller to make that
65
+ * decision in the open; the four caches in this directory all take the same
66
+ * route, and say so where they do it.
67
+ */
68
+ export default function getCanonicalModelInstance<T>(target: T): T | null {
69
+ const modelClass: NoArgConstructor | undefined = (
70
+ target as { constructor?: NoArgConstructor } | null | undefined
71
+ )?.constructor;
72
+
73
+ if (typeof modelClass !== "function") {
74
+ return null;
75
+ }
76
+
77
+ const cached: unknown = canonicalInstanceCache.get(modelClass);
78
+
79
+ if (cached) {
80
+ return cached as T;
81
+ }
82
+
83
+ if (beingConstructed.has(modelClass)) {
84
+ return null;
85
+ }
86
+
87
+ let canonical: T;
88
+
89
+ beingConstructed.add(modelClass);
90
+
91
+ try {
92
+ canonical = Object.freeze(new modelClass()) as T;
93
+ } catch {
94
+ return null;
95
+ } finally {
96
+ beingConstructed.delete(modelClass);
97
+ }
98
+
99
+ canonicalInstanceCache.set(modelClass, canonical);
100
+
101
+ return canonical;
102
+ }
@@ -1,4 +1,5 @@
1
1
  import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
2
+ import getCanonicalModelInstance from "./CanonicalModelInstance";
2
3
  import Dictionary from "../Dictionary";
3
4
  import { JSONObject } from "../JSON";
4
5
  import { ReflectionMetadataType } from "../Reflection";
@@ -99,9 +100,12 @@ type GetTableColumnsFunction = <T extends BaseModel>(
99
100
  ) => Dictionary<TableColumnMetadata>;
100
101
 
101
102
  /*
102
- * Per-class cache. Safe to key on the constructor because every decorated
103
- * column is initialised to `undefined` in the class body, so Object.keys()
104
- * is identical for every instance of a class (see OwnerOnlyColumn.ts).
103
+ * Per-class cache, keyed on the constructor and built from a canonical
104
+ * instance of that class - never from the instance that happened to ask
105
+ * first. A caller that had deleted a column off its own instance (BaseAPI's
106
+ * create path used to delete `_id`) would otherwise define the class's column
107
+ * list without that column for the whole process, and every response for that
108
+ * model would lose it. See CanonicalModelInstance.ts.
105
109
  */
106
110
  const tableColumnsCache: WeakMap<
107
111
  { new (): BaseModel },
@@ -118,13 +122,15 @@ export const getTableColumns: GetTableColumnsFunction = <T extends BaseModel>(
118
122
  tableColumnsCache.get(modelClass);
119
123
 
120
124
  if (!cached) {
125
+ const canonical: T | null = getCanonicalModelInstance(target);
126
+ const metadataSource: T = canonical || target;
121
127
  const dictonary: Dictionary<TableColumnMetadata> = {};
122
- const keys: Array<string> = Object.keys(target);
128
+ const keys: Array<string> = Object.keys(metadataSource);
123
129
 
124
130
  for (const key of keys) {
125
131
  const metadata: TableColumnMetadata | undefined = Reflect.getMetadata(
126
132
  tableColumn,
127
- target,
133
+ metadataSource,
128
134
  key,
129
135
  ) as TableColumnMetadata | undefined;
130
136
  if (metadata) {
@@ -133,7 +139,15 @@ export const getTableColumns: GetTableColumnsFunction = <T extends BaseModel>(
133
139
  }
134
140
 
135
141
  cached = dictonary;
136
- tableColumnsCache.set(modelClass, cached);
142
+
143
+ /*
144
+ * No canonical instance (see CanonicalModelInstance): answer from the
145
+ * instance we were handed, but do NOT cache it for the class - that
146
+ * instance may be a mutilated one, and a cached answer outlives it.
147
+ */
148
+ if (canonical) {
149
+ tableColumnsCache.set(modelClass, cached);
150
+ }
137
151
  }
138
152
 
139
153
  /*
@@ -0,0 +1,29 @@
1
+ /*
2
+ * The two periods a self-hosted Enterprise Edition install runs without a
3
+ * current license. They are different periods with different lengths, and
4
+ * the product must never call one by the other's name:
5
+ *
6
+ * trial an Enterprise install that has never had a license, counted from
7
+ * GlobalConfig.enterpriseEditionFirstSeenAt
8
+ * grace a license that expired (a verified license's signed expiry, or an
9
+ * unverified legacy license's stored expiry column), counted from
10
+ * its expiry
11
+ *
12
+ * Until either ends nothing changes; after it, enterprise configuration
13
+ * becomes read-only and SSO, SCIM and audit logging stop
14
+ * (EnterpriseEdition.isFeatureActive) until a license is activated.
15
+ *
16
+ * They live here, with no server dependency, so the copy that states them in
17
+ * the browser (the edition dialog, the enterprise banners) derives the
18
+ * numbers from the same place the license classifier does. Server code reads
19
+ * them through Common/Server/Enterprise/EnterpriseLicenseSnapshot.
20
+ */
21
+
22
+ // How long an expired license keeps working, counted from its expiry.
23
+ export const ENTERPRISE_LICENSE_GRACE_PERIOD_IN_DAYS: number = 30;
24
+
25
+ /*
26
+ * How long an Enterprise install with no license at all is on trial, counted
27
+ * from GlobalConfig.enterpriseEditionFirstSeenAt.
28
+ */
29
+ export const ENTERPRISE_LICENSE_TRIAL_PERIOD_IN_DAYS: number = 14;
package/Types/IP/IPv6.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import BadDataException from "../Exception/BadDataException";
2
2
  import IP from "./IP";
3
3
 
4
- export default class IPv4 extends IP {
4
+ /*
5
+ * The class used to be declared `class IPv4 extends IP` here — a copy-paste
6
+ * that the default export hid from every import site, while leaving
7
+ * IPv6.name === "IPv4" in error messages, serialized output and API docs.
8
+ */
9
+ export default class IPv6 extends IP {
5
10
  public constructor(ip: string) {
6
11
  super(ip);
7
12
 
@@ -497,8 +497,13 @@ export default class MonitorStep extends DatabaseProperty {
497
497
  return this;
498
498
  }
499
499
 
500
+ /*
501
+ * `undefined` clears it. The form needs that: a destination that no longer
502
+ * parses must not leave the previously parsed one sitting in the step,
503
+ * where it would be saved as if the operator had meant it.
504
+ */
500
505
  public setMonitorDestination(
501
- monitorDestination: URL | IP | Hostname,
506
+ monitorDestination: URL | IP | Hostname | undefined,
502
507
  ): MonitorStep {
503
508
  this.data!.monitorDestination = monitorDestination;
504
509
  return this;
@@ -897,7 +897,7 @@ const guestNotBackedUpTemplate: ProxmoxAlertTemplate = {
897
897
  /*
898
898
  * Cluster-level gauge from the backup-info collector — one
899
899
  * series, no `id` label, so no groupBy: one incident per
900
- * cluster. Per-guest naming belongs to the breakdown table
900
+ * cluster. Per-guest naming belongs to the Affected Resources list
901
901
  * (pve_not_backed_up_info grouped by `id`), not the alert.
902
902
  */
903
903
  metricName: "pve_not_backed_up_total",
@@ -0,0 +1,110 @@
1
+ /*
2
+ * Per-monitor, per-day status durations for the status-page uptime bars.
3
+ *
4
+ * WHY THIS TYPE EXISTS
5
+ *
6
+ * The bars used to be painted from raw MonitorStatusTimeline rows shipped to
7
+ * the browser under a single `limit: LIMIT_MAX` (10,000) across EVERY monitor
8
+ * on the page, sorted `startsAt DESC`.
9
+ *
10
+ * That cap is a silent, history-destroying bound. Measured on a real status
11
+ * page: 254,550 rows matched the 60-day window and 10,000 came back - 3.9%.
12
+ * The oldest surviving row started four days before the request, so 56 of the
13
+ * 60 bars were painted from data that had been dropped.
14
+ *
15
+ * Worse, the cap is GLOBAL across monitors and the sort is newest-first, so a
16
+ * few high-churn monitors starve the quiet ones out of the result set
17
+ * entirely. On the page that reported this, three flapping monitors held
18
+ * 9,995 of the 10,000 slots. A quiet, healthy monitor's covering row has an
19
+ * OLD `startsAt` and therefore sorts last - so the healthier a monitor is,
20
+ * the more likely it is to lose its whole history to a noisy neighbour.
21
+ *
22
+ * Shipping more rows cannot fix it. One row serializes to ~431 bytes in this
23
+ * codebase's typed JSON, so 254,550 rows is ~105 MB - into a response that is
24
+ * held in a 500-entry in-memory cache on the hottest public endpoint, and
25
+ * then filtered per-bar on the client's main thread.
26
+ *
27
+ * So the server sends DURATIONS instead of rows. The size is structural -
28
+ * O(monitors x days x statuses) - rather than O(status transitions), and it
29
+ * cannot be blown up by a flapping monitor.
30
+ */
31
+
32
+ import ObjectID from "../ObjectID";
33
+
34
+ /**
35
+ * Seconds spent in one monitor status, inside one day bucket.
36
+ */
37
+ export interface UptimeStatusDuration {
38
+ monitorStatusId: ObjectID;
39
+ seconds: number;
40
+ }
41
+
42
+ /**
43
+ * One monitor's reading for one day bucket.
44
+ */
45
+ export interface UptimeDayBucket {
46
+ /* Start of the bucket, as a UTC instant. */
47
+ bucketStart: Date;
48
+
49
+ /* End of the bucket, as a UTC instant. */
50
+ bucketEnd: Date;
51
+
52
+ /*
53
+ * Wall-clock seconds in the bucket.
54
+ *
55
+ * NOT hardcoded to 86400. The window's first and last buckets are clipped
56
+ * to the window, and a local calendar day that crosses a DST boundary is
57
+ * genuinely 23 or 25 hours long.
58
+ */
59
+ daySeconds: number;
60
+
61
+ /*
62
+ * Seconds of this bucket actually covered by a timeline row.
63
+ *
64
+ * This is the field the whole fix turns on. `coveredSeconds === 0` means
65
+ * "nothing was ever recorded for this day" - the monitor did not exist yet,
66
+ * or there is a hole in the record. Such a day must never be painted as
67
+ * uptime, which is exactly what the old code did by falling through to the
68
+ * status page's `defaultBarColor` (green on 4,642 status pages).
69
+ *
70
+ * `0 < coveredSeconds < daySeconds` is NOT a no-data day. It is a real
71
+ * reading of a shorter interval - the day a monitor was created, say - and
72
+ * its percentage is taken over what was measured.
73
+ */
74
+ coveredSeconds: number;
75
+
76
+ /* Seconds spent in each status, summed within the bucket. */
77
+ statusDurations: Array<UptimeStatusDuration>;
78
+ }
79
+
80
+ /**
81
+ * Every day bucket for one monitor.
82
+ */
83
+ export interface MonitorUptimeDailyAggregate {
84
+ monitorId: ObjectID;
85
+ buckets: Array<UptimeDayBucket>;
86
+ }
87
+
88
+ /**
89
+ * The full aggregate for a status page request.
90
+ */
91
+ export interface UptimeDailyAggregate {
92
+ monitors: Array<MonitorUptimeDailyAggregate>;
93
+
94
+ /*
95
+ * False when the server could not vouch for the whole window.
96
+ *
97
+ * There is no silent cap in the aggregate path, so this is normally true.
98
+ * It exists because a bound that is ever added later must SHOW, not be
99
+ * absorbed into a green bar - which is the failure this whole change is
100
+ * about. When false, `completeFrom` says where the trustworthy data starts
101
+ * and the client renders everything older as no-data rather than guessing.
102
+ */
103
+ isComplete: boolean;
104
+
105
+ /*
106
+ * The earliest instant the aggregate can vouch for, when `isComplete` is
107
+ * false. Null when the whole window is covered.
108
+ */
109
+ completeFrom: Date | null;
110
+ }