@oneuptime/common 12.0.1 → 12.0.3

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 (385) hide show
  1. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
  2. package/Models/DatabaseModels/Host.ts +12 -4
  3. package/Models/DatabaseModels/Index.ts +2 -0
  4. package/Models/DatabaseModels/KubernetesContainer.ts +5 -4
  5. package/Models/DatabaseModels/KubernetesResource.ts +8 -7
  6. package/Models/DatabaseModels/LogDropFilter.ts +9 -20
  7. package/Models/DatabaseModels/PodmanResource.ts +6 -6
  8. package/Models/DatabaseModels/ServiceLevelObjective.ts +91 -0
  9. package/Models/DatabaseModels/StatusPage.ts +95 -0
  10. package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
  11. package/Models/DatabaseModels/StatusPageResource.ts +73 -0
  12. package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
  13. package/Server/API/BaseAPI.ts +13 -2
  14. package/Server/API/DashboardAPI.ts +39 -0
  15. package/Server/API/TeamMemberAPI.ts +85 -0
  16. package/Server/EnvironmentConfig.ts +31 -1
  17. package/Server/Infrastructure/GlobalCache.ts +115 -0
  18. package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.ts +84 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.ts +40 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.ts +131 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.ts +25 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  25. package/Server/Middleware/ProjectAuthorization.ts +66 -4
  26. package/Server/Services/AlertStateTimelineService.ts +20 -0
  27. package/Server/Services/BillingService.ts +600 -51
  28. package/Server/Services/CephClusterService.ts +27 -45
  29. package/Server/Services/CephResourceService.ts +43 -4
  30. package/Server/Services/CloudResourceService.ts +24 -42
  31. package/Server/Services/DatabaseService.ts +198 -6
  32. package/Server/Services/DockerHostService.ts +20 -38
  33. package/Server/Services/DockerResourceService.ts +62 -8
  34. package/Server/Services/DockerSwarmClusterService.ts +28 -46
  35. package/Server/Services/DockerSwarmResourceService.ts +53 -4
  36. package/Server/Services/HostService.ts +47 -57
  37. package/Server/Services/IncidentStateTimelineService.ts +20 -0
  38. package/Server/Services/Index.ts +2 -0
  39. package/Server/Services/IoTDeviceService.ts +1 -17
  40. package/Server/Services/IoTFleetService.ts +20 -38
  41. package/Server/Services/KubernetesClusterService.ts +18 -36
  42. package/Server/Services/KubernetesContainerService.ts +50 -9
  43. package/Server/Services/KubernetesResourceService.ts +53 -7
  44. package/Server/Services/LabelService.ts +153 -1
  45. package/Server/Services/MetricTypeService.ts +84 -0
  46. package/Server/Services/MonitorService.ts +146 -14
  47. package/Server/Services/MonitorStatusTimelineService.ts +29 -0
  48. package/Server/Services/MonitorTemplateService.ts +65 -0
  49. package/Server/Services/PodmanHostService.ts +20 -38
  50. package/Server/Services/PodmanResourceService.ts +62 -8
  51. package/Server/Services/ProjectService.ts +165 -35
  52. package/Server/Services/ProxmoxClusterService.ts +24 -42
  53. package/Server/Services/ProxmoxResourceService.ts +43 -4
  54. package/Server/Services/RumApplicationService.ts +20 -38
  55. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
  56. package/Server/Services/ServerlessFunctionService.ts +25 -43
  57. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +426 -0
  58. package/Server/Services/ServiceLevelObjectiveService.ts +39 -0
  59. package/Server/Services/ServiceService.ts +299 -73
  60. package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
  61. package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
  62. package/Server/Services/StatusPageService.ts +95 -36
  63. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +18 -1
  64. package/Server/Services/StatusPageSubscriberService.ts +3 -0
  65. package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
  66. package/Server/Services/TelemetryEntityService.ts +1 -0
  67. package/Server/Types/Database/JSONColumnQuery.ts +621 -0
  68. package/Server/Types/Database/Permissions/PublicPermission.ts +9 -2
  69. package/Server/Types/Database/QueryHelper.ts +17 -32
  70. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
  71. package/Server/Utils/Database/TruncateColumnValue.ts +84 -0
  72. package/Server/Utils/Monitor/MonitorResource.ts +63 -36
  73. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
  74. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
  75. package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
  76. package/Server/Utils/SingleFlight.ts +83 -0
  77. package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
  78. package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
  79. package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
  80. package/Server/Utils/Telemetry/Telemetry.ts +351 -122
  81. package/Tests/App/Dashboard/UsersTableGroupsByPerson.test.tsx +448 -0
  82. package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
  83. package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
  84. package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
  85. package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
  86. package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +704 -0
  87. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
  88. package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +303 -0
  89. package/Tests/Server/Infrastructure/GlobalCache.test.ts +226 -0
  90. package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
  91. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +350 -0
  92. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyHeader.test.ts +362 -0
  93. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +687 -0
  94. package/Tests/Server/Services/BillingService.test.ts +78 -3
  95. package/Tests/Server/Services/BillingServiceChangePlanCancel.test.ts +645 -0
  96. package/Tests/Server/Services/BillingServiceTrialPlanChange.test.ts +1005 -0
  97. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
  98. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
  99. package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +503 -0
  100. package/Tests/Server/Services/HostIpAddressesColumnWidth.test.ts +198 -0
  101. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +658 -0
  102. package/Tests/Server/Services/InventoryResourceNameColumnWidth.test.ts +500 -0
  103. package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +586 -0
  104. package/Tests/Server/Services/InventoryUpsertTruncationGuard.test.ts +1242 -0
  105. package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
  106. package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
  107. package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
  108. package/Tests/Server/Services/ProjectServiceChangePlan.test.ts +650 -0
  109. package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +1 -0
  110. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +636 -0
  111. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +770 -0
  112. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +130 -0
  113. package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
  114. package/Tests/Server/Services/SloMonitorLabelRuleHooks.test.ts +352 -0
  115. package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
  116. package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
  117. package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
  118. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +29 -13
  119. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +69 -8
  120. package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +593 -0
  121. package/Tests/Server/Types/Database/Permissions/PublicPermission.test.ts +495 -0
  122. package/Tests/Server/Types/Database/QueryUtil.test.ts +113 -0
  123. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
  124. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
  125. package/Tests/Server/Utils/Database/TruncateColumnValue.test.ts +179 -0
  126. package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
  127. package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
  128. package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
  129. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
  130. package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
  131. package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
  132. package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
  133. package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
  134. package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
  135. package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
  136. package/Tests/Types/Decimal.test.ts +37 -0
  137. package/Tests/Types/Events/Recurring.test.ts +157 -0
  138. package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
  139. package/Tests/Types/Port.test.ts +38 -0
  140. package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
  141. package/Tests/UI/Components/ModelTable/ModelTableGroupsProjectUsers.test.tsx +375 -0
  142. package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +196 -0
  143. package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
  144. package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
  145. package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +739 -0
  146. package/Tests/UI/Utils/TeamMembersByUser.test.ts +633 -0
  147. package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
  148. package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
  149. package/Tests/Utils/StatusPage/ReportPeriod.test.ts +218 -0
  150. package/Tests/Utils/Telemetry/HostIpAddresses.test.ts +291 -0
  151. package/Types/CustomField/CustomFieldDefinition.ts +24 -0
  152. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  153. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  154. package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
  155. package/Types/Dashboard/DashboardTemplates.ts +397 -0
  156. package/Types/Database/BigIntColumnTransformer.ts +74 -0
  157. package/Types/Database/DatabaseProperty.ts +26 -0
  158. package/Types/Database/NumericColumnValue.ts +128 -0
  159. package/Types/Date.ts +112 -0
  160. package/Types/Decimal.ts +16 -4
  161. package/Types/Events/Recurring.ts +99 -1
  162. package/Types/Permission.ts +48 -0
  163. package/Types/Port.ts +16 -4
  164. package/Types/StatusPage/StatusPageReport.ts +11 -0
  165. package/Types/StatusPage/StatusPageReportPeriodType.ts +21 -0
  166. package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
  167. package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
  168. package/UI/Components/ModelTable/CustomFieldColumns.tsx +2 -6
  169. package/UI/Components/ModelTable/useCustomFieldColumns.ts +21 -2
  170. package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +305 -0
  171. package/UI/Utils/TeamMembersByUser.ts +302 -0
  172. package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
  173. package/Utils/Dashboard/Components/Index.ts +7 -0
  174. package/Utils/StatusPage/ReportPeriod.ts +236 -0
  175. package/Utils/Telemetry/HostIpAddresses.ts +98 -0
  176. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
  177. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  178. package/build/dist/Models/DatabaseModels/Host.js +12 -4
  179. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  180. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  181. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  182. package/build/dist/Models/DatabaseModels/KubernetesContainer.js +4 -4
  183. package/build/dist/Models/DatabaseModels/KubernetesContainer.js.map +1 -1
  184. package/build/dist/Models/DatabaseModels/KubernetesResource.js +7 -7
  185. package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
  187. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/PodmanResource.js +6 -6
  189. package/build/dist/Models/DatabaseModels/PodmanResource.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +87 -0
  191. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/StatusPage.js +98 -0
  193. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
  195. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
  196. package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
  197. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
  199. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  200. package/build/dist/Server/API/BaseAPI.js +11 -1
  201. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  202. package/build/dist/Server/API/DashboardAPI.js +39 -0
  203. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  204. package/build/dist/Server/API/TeamMemberAPI.js +57 -2
  205. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  206. package/build/dist/Server/EnvironmentConfig.js +27 -1
  207. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  208. package/build/dist/Server/Infrastructure/GlobalCache.js +91 -0
  209. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  210. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
  211. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
  212. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js +45 -0
  213. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js.map +1 -0
  214. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js +31 -0
  215. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js.map +1 -0
  216. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js +90 -0
  217. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js.map +1 -0
  218. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js +14 -0
  219. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js.map +1 -0
  220. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
  221. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
  222. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  223. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  224. package/build/dist/Server/Middleware/ProjectAuthorization.js +59 -4
  225. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  226. package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
  227. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  228. package/build/dist/Server/Services/BillingService.js +466 -36
  229. package/build/dist/Server/Services/BillingService.js.map +1 -1
  230. package/build/dist/Server/Services/CephClusterService.js +26 -39
  231. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  232. package/build/dist/Server/Services/CephResourceService.js +28 -3
  233. package/build/dist/Server/Services/CephResourceService.js.map +1 -1
  234. package/build/dist/Server/Services/CloudResourceService.js +23 -36
  235. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  236. package/build/dist/Server/Services/DatabaseService.js +155 -2
  237. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  238. package/build/dist/Server/Services/DockerHostService.js +19 -32
  239. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  240. package/build/dist/Server/Services/DockerResourceService.js +34 -4
  241. package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
  242. package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -40
  243. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  244. package/build/dist/Server/Services/DockerSwarmResourceService.js +28 -3
  245. package/build/dist/Server/Services/DockerSwarmResourceService.js.map +1 -1
  246. package/build/dist/Server/Services/HostService.js +58 -64
  247. package/build/dist/Server/Services/HostService.js.map +1 -1
  248. package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
  249. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  250. package/build/dist/Server/Services/Index.js +2 -0
  251. package/build/dist/Server/Services/Index.js.map +1 -1
  252. package/build/dist/Server/Services/IoTDeviceService.js +1 -8
  253. package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
  254. package/build/dist/Server/Services/IoTFleetService.js +19 -32
  255. package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
  256. package/build/dist/Server/Services/KubernetesClusterService.js +17 -30
  257. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  258. package/build/dist/Server/Services/KubernetesContainerService.js +29 -3
  259. package/build/dist/Server/Services/KubernetesContainerService.js.map +1 -1
  260. package/build/dist/Server/Services/KubernetesResourceService.js +32 -4
  261. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  262. package/build/dist/Server/Services/LabelService.js +127 -0
  263. package/build/dist/Server/Services/LabelService.js.map +1 -1
  264. package/build/dist/Server/Services/MetricTypeService.js +74 -0
  265. package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
  266. package/build/dist/Server/Services/MonitorService.js +128 -9
  267. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  268. package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
  269. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  270. package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
  271. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  272. package/build/dist/Server/Services/PodmanHostService.js +19 -32
  273. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  274. package/build/dist/Server/Services/PodmanResourceService.js +34 -4
  275. package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
  276. package/build/dist/Server/Services/ProjectService.js +135 -21
  277. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  278. package/build/dist/Server/Services/ProxmoxClusterService.js +23 -36
  279. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  280. package/build/dist/Server/Services/ProxmoxResourceService.js +28 -3
  281. package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
  282. package/build/dist/Server/Services/RumApplicationService.js +19 -32
  283. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  284. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
  285. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  286. package/build/dist/Server/Services/ServerlessFunctionService.js +24 -37
  287. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  288. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +347 -0
  289. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -0
  290. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +33 -1
  291. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  292. package/build/dist/Server/Services/ServiceService.js +236 -61
  293. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  294. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
  295. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
  296. package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
  297. package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
  298. package/build/dist/Server/Services/StatusPageService.js +69 -46
  299. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  300. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +17 -1
  301. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  302. package/build/dist/Server/Services/StatusPageSubscriberService.js +3 -0
  303. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  304. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
  305. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
  306. package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
  307. package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
  308. package/build/dist/Server/Types/Database/JSONColumnQuery.js +402 -0
  309. package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -0
  310. package/build/dist/Server/Types/Database/Permissions/PublicPermission.js +9 -2
  311. package/build/dist/Server/Types/Database/Permissions/PublicPermission.js.map +1 -1
  312. package/build/dist/Server/Types/Database/QueryHelper.js +17 -27
  313. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  314. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
  315. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  316. package/build/dist/Server/Utils/Database/TruncateColumnValue.js +32 -0
  317. package/build/dist/Server/Utils/Database/TruncateColumnValue.js.map +1 -0
  318. package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
  319. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  320. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
  321. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  322. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
  323. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
  324. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
  325. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
  326. package/build/dist/Server/Utils/SingleFlight.js +76 -0
  327. package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
  328. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
  329. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
  330. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
  331. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  332. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
  333. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
  334. package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
  335. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  336. package/build/dist/Types/CustomField/CustomFieldDefinition.js +2 -0
  337. package/build/dist/Types/CustomField/CustomFieldDefinition.js.map +1 -0
  338. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  339. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  340. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  341. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  342. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
  343. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
  344. package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
  345. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  346. package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
  347. package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
  348. package/build/dist/Types/Database/DatabaseProperty.js +25 -0
  349. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  350. package/build/dist/Types/Database/NumericColumnValue.js +97 -0
  351. package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
  352. package/build/dist/Types/Date.js +68 -0
  353. package/build/dist/Types/Date.js.map +1 -1
  354. package/build/dist/Types/Decimal.js +14 -3
  355. package/build/dist/Types/Decimal.js.map +1 -1
  356. package/build/dist/Types/Events/Recurring.js +63 -0
  357. package/build/dist/Types/Events/Recurring.js.map +1 -1
  358. package/build/dist/Types/Permission.js +42 -0
  359. package/build/dist/Types/Permission.js.map +1 -1
  360. package/build/dist/Types/Port.js +15 -5
  361. package/build/dist/Types/Port.js.map +1 -1
  362. package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js +22 -0
  363. package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js.map +1 -0
  364. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
  365. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
  366. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
  367. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
  368. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  369. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +18 -2
  370. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
  371. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +213 -0
  372. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -0
  373. package/build/dist/UI/Utils/TeamMembersByUser.js +195 -0
  374. package/build/dist/UI/Utils/TeamMembersByUser.js.map +1 -0
  375. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
  376. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
  377. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  378. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  379. package/build/dist/Utils/StatusPage/ReportPeriod.js +131 -0
  380. package/build/dist/Utils/StatusPage/ReportPeriod.js.map +1 -0
  381. package/build/dist/Utils/Telemetry/HostIpAddresses.js +82 -0
  382. package/build/dist/Utils/Telemetry/HostIpAddresses.js.map +1 -0
  383. package/jest.config.json +2 -0
  384. package/package.json +1 -1
  385. package/tsconfig.json +12 -1
@@ -2,6 +2,7 @@ import DatabaseService from "./DatabaseService";
2
2
  import Model from "../../Models/DatabaseModels/ServerlessFunction";
3
3
  import Label from "../../Models/DatabaseModels/Label";
4
4
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
5
+ import ResourceHeartbeat from "../Utils/Telemetry/ResourceHeartbeat";
5
6
  import ObjectID from "../../Types/ObjectID";
6
7
  import QueryHelper from "../Types/Database/QueryHelper";
7
8
  import OneUptimeDate from "../../Types/Date";
@@ -153,7 +154,6 @@ export class Service extends DatabaseService<Model> {
153
154
  runtimeVersion?: string | undefined;
154
155
  },
155
156
  ): Promise<void> {
156
- const cacheKey: string = serverlessFunctionId.toString();
157
157
  const extrasFingerprint: string = crypto
158
158
  .createHash("sha1")
159
159
  .update(
@@ -170,73 +170,55 @@ export class Service extends DatabaseService<Model> {
170
170
  )
171
171
  .digest("hex");
172
172
 
173
- let cached: string | null = null;
174
- try {
175
- cached = await GlobalCache.getString(LAST_SEEN_CACHE_NAMESPACE, cacheKey);
176
- } catch {
177
- /*
178
- * Cache unavailable — fail open and refresh lastSeenAt anyway. A
179
- * cache error must never skip the DB write below, otherwise the
180
- * resource is wrongly marked "disconnected" while telemetry is
181
- * still flowing. Mirrors shouldRunMaintenance's fail-open stance.
182
- */
183
- cached = null;
184
- }
185
-
186
- if (cached === extrasFingerprint) {
187
- return; // same data was written recently
188
- }
189
-
190
- try {
191
- await GlobalCache.setString(
192
- LAST_SEEN_CACHE_NAMESPACE,
193
- cacheKey,
194
- extrasFingerprint,
195
- { expiresInSeconds: LAST_SEEN_THROTTLE_SECONDS },
196
- );
197
- } catch {
198
- // Best-effort throttle write; proceed with the DB update regardless.
199
- }
200
-
201
173
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
202
- const data: any = {
174
+ const liveness: any = {
203
175
  lastSeenAt: OneUptimeDate.getCurrentDate(),
204
176
  otelCollectorStatus: "connected",
205
177
  };
206
178
 
179
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
180
+ const metadata: any = {};
181
+
207
182
  if (extra?.agentVersion) {
208
- data.agentVersion = extra.agentVersion;
183
+ metadata.agentVersion = extra.agentVersion;
209
184
  }
210
185
  if (extra?.cloudPlatform) {
211
- data.cloudPlatform = extra.cloudPlatform;
186
+ metadata.cloudPlatform = extra.cloudPlatform;
212
187
  }
213
188
  if (extra?.cloudProvider) {
214
- data.cloudProvider = extra.cloudProvider;
189
+ metadata.cloudProvider = extra.cloudProvider;
215
190
  }
216
191
  if (extra?.cloudRegion) {
217
- data.cloudRegion = extra.cloudRegion;
192
+ metadata.cloudRegion = extra.cloudRegion;
218
193
  }
219
194
  if (extra?.cloudAccountId) {
220
- data.cloudAccountId = extra.cloudAccountId;
195
+ metadata.cloudAccountId = extra.cloudAccountId;
221
196
  }
222
197
  if (extra?.functionVersion) {
223
- data.functionVersion = extra.functionVersion;
198
+ metadata.functionVersion = extra.functionVersion;
224
199
  }
225
200
  if (extra?.runtimeName) {
226
- data.runtimeName = extra.runtimeName;
201
+ metadata.runtimeName = extra.runtimeName;
227
202
  }
228
203
  if (extra?.runtimeVersion) {
229
- data.runtimeVersion = extra.runtimeVersion;
204
+ metadata.runtimeVersion = extra.runtimeVersion;
230
205
  }
231
206
 
232
207
  /*
233
- * Heartbeat write: a single-statement UPDATE with no hooks and no
234
- * `version` bump, avoiding the hot-row Postgres lock convoy that the
235
- * full updateOneById pipeline causes. See ServiceService.updateLastSeen.
208
+ * One gated, non-blocking heartbeat write. The gates, the fail-open /
209
+ * fail-closed split and the liveness-only fallback all live in
210
+ * ResourceHeartbeat see there for why this row's throttle used to
211
+ * provide no throttling at all.
236
212
  */
237
- await this.updateColumnsByIdWithoutHooks({
213
+ await ResourceHeartbeat.write({
214
+ service: this,
238
215
  id: serverlessFunctionId,
239
- data: data,
216
+ cacheNamespace: LAST_SEEN_CACHE_NAMESPACE,
217
+ throttleInSeconds: LAST_SEEN_THROTTLE_SECONDS,
218
+ liveness: liveness,
219
+ metadata: metadata,
220
+ fingerprint: extrasFingerprint,
221
+ describe: `serverless function ${serverlessFunctionId.toString()}`,
240
222
  });
241
223
  }
242
224
 
@@ -0,0 +1,426 @@
1
+ import Monitor from "../../Models/DatabaseModels/Monitor";
2
+ import ServiceLevelObjective from "../../Models/DatabaseModels/ServiceLevelObjective";
3
+ import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
4
+ import PartialEntity from "../../Types/Database/PartialEntity";
5
+ import ObjectID from "../../Types/ObjectID";
6
+ import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
7
+ import logger, { LogAttributes } from "../Utils/Logger";
8
+ import MonitorService from "./MonitorService";
9
+ import ServiceLevelObjectiveService from "./ServiceLevelObjectiveService";
10
+
11
+ /**
12
+ * What a sync did, so callers (and tests) can assert on the outcome without
13
+ * re-reading the SLO.
14
+ */
15
+ export interface SloMonitorSyncResult {
16
+ monitorIdsAdded: Array<string>;
17
+ monitorIdsRemoved: Array<string>;
18
+ }
19
+
20
+ function emptyResult(): SloMonitorSyncResult {
21
+ return { monitorIdsAdded: [], monitorIdsRemoved: [] };
22
+ }
23
+
24
+ function toIdSet(
25
+ items: Array<{ id?: ObjectID | null }> | undefined,
26
+ ): Set<string> {
27
+ const ids: Set<string> = new Set<string>();
28
+
29
+ for (const item of items || []) {
30
+ const id: string = item?.id?.toString() || "";
31
+
32
+ if (id) {
33
+ ids.add(id);
34
+ }
35
+ }
36
+
37
+ return ids;
38
+ }
39
+
40
+ function toMonitors(ids: Iterable<string>): Array<Monitor> {
41
+ const monitors: Array<Monitor> = [];
42
+
43
+ for (const id of ids) {
44
+ const monitor: Monitor = new Monitor();
45
+ monitor.id = new ObjectID(id);
46
+ monitors.push(monitor);
47
+ }
48
+
49
+ return monitors;
50
+ }
51
+
52
+ function isSameSet(a: Set<string>, b: Set<string>): boolean {
53
+ if (a.size !== b.size) {
54
+ return false;
55
+ }
56
+
57
+ for (const value of a) {
58
+ if (!b.has(value)) {
59
+ return false;
60
+ }
61
+ }
62
+
63
+ return true;
64
+ }
65
+
66
+ /**
67
+ * Keeps an SLO's monitor list in step with its label rule.
68
+ *
69
+ * An SLO can name a set of monitor labels ("Auto-Add Monitors With Labels").
70
+ * Every monitor in the project carrying at least one of them belongs to the
71
+ * SLO, and stops belonging to it the moment it carries none. Two entry points
72
+ * drive that, because the membership can be invalidated from either side:
73
+ *
74
+ * - the SLO side (its rule changed) -> syncMonitorsForSlo
75
+ * - the monitor side (its labels changed) -> syncSlosForMonitor
76
+ *
77
+ * Both write through ServiceLevelObjective.autoAddedMonitors, which records
78
+ * which attachments the rule owns. Only those are ever detached, so a monitor
79
+ * a human attached by hand survives every rule evaluation — including the one
80
+ * that runs when the rule is deleted.
81
+ */
82
+ export class ServiceLevelObjectiveMonitorRuleEngineServiceClass {
83
+ /**
84
+ * Re-evaluates one SLO's label rule against every monitor in its project.
85
+ * Use when the SLO's rule changed (created, edited, or cleared) — it is the
86
+ * authoritative, self-healing path and repairs any drift it finds.
87
+ */
88
+ @CaptureSpan()
89
+ public async syncMonitorsForSlo(data: {
90
+ serviceLevelObjectiveId: ObjectID;
91
+ }): Promise<SloMonitorSyncResult> {
92
+ const slo: ServiceLevelObjective | null =
93
+ await ServiceLevelObjectiveService.findOneById({
94
+ id: data.serviceLevelObjectiveId,
95
+ select: {
96
+ _id: true,
97
+ projectId: true,
98
+ monitorLabels: {
99
+ _id: true,
100
+ },
101
+ monitors: {
102
+ _id: true,
103
+ },
104
+ autoAddedMonitors: {
105
+ _id: true,
106
+ },
107
+ },
108
+ props: {
109
+ isRoot: true,
110
+ },
111
+ });
112
+
113
+ if (!slo || !slo.id || !slo.projectId) {
114
+ return emptyResult();
115
+ }
116
+
117
+ const ruleLabelIds: Set<string> = toIdSet(slo.monitorLabels);
118
+
119
+ /*
120
+ * No rule (or the rule was just cleared) means nothing matches, which in
121
+ * turn detaches everything the rule had attached. Deleting the rule
122
+ * therefore undoes the rule rather than leaving its monitors stranded on
123
+ * an SLO nobody remembers configuring.
124
+ */
125
+ const matchedMonitorIds: Set<string> =
126
+ ruleLabelIds.size === 0
127
+ ? new Set<string>()
128
+ : await this.findMonitorIdsWithAnyLabel({
129
+ projectId: slo.projectId,
130
+ labelIds: ruleLabelIds,
131
+ });
132
+
133
+ return await this.writeMembership({
134
+ slo: slo,
135
+ attachedMonitorIds: toIdSet(slo.monitors),
136
+ autoAddedMonitorIds: toIdSet(slo.autoAddedMonitors),
137
+ matchedMonitorIds: matchedMonitorIds,
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Re-evaluates every label rule in the project against a single monitor.
143
+ * Use when the monitor's labels changed: it touches only this monitor's
144
+ * membership, so it costs one query per project regardless of how many
145
+ * monitors the rules match.
146
+ */
147
+ @CaptureSpan()
148
+ public async syncSlosForMonitor(data: {
149
+ monitorId: ObjectID;
150
+ projectId?: ObjectID | undefined;
151
+ }): Promise<Array<SloMonitorSyncResult>> {
152
+ const monitor: Monitor | null = await MonitorService.findOneById({
153
+ id: data.monitorId,
154
+ select: {
155
+ _id: true,
156
+ projectId: true,
157
+ labels: {
158
+ _id: true,
159
+ },
160
+ },
161
+ props: {
162
+ isRoot: true,
163
+ },
164
+ });
165
+
166
+ if (!monitor || !monitor.id) {
167
+ return [];
168
+ }
169
+
170
+ const projectId: ObjectID | undefined =
171
+ monitor.projectId || data.projectId || undefined;
172
+
173
+ if (!projectId) {
174
+ return [];
175
+ }
176
+
177
+ const monitorLabelIds: Set<string> = toIdSet(monitor.labels);
178
+ const monitorId: string = monitor.id.toString();
179
+
180
+ const slos: Array<ServiceLevelObjective> =
181
+ await ServiceLevelObjectiveService.findBy({
182
+ query: {
183
+ projectId: projectId,
184
+ },
185
+ select: {
186
+ _id: true,
187
+ projectId: true,
188
+ monitorLabels: {
189
+ _id: true,
190
+ },
191
+ monitors: {
192
+ _id: true,
193
+ },
194
+ autoAddedMonitors: {
195
+ _id: true,
196
+ },
197
+ },
198
+ limit: LIMIT_PER_PROJECT,
199
+ skip: 0,
200
+ props: {
201
+ isRoot: true,
202
+ },
203
+ });
204
+
205
+ const results: Array<SloMonitorSyncResult> = [];
206
+
207
+ for (const slo of slos) {
208
+ const ruleLabelIds: Set<string> = toIdSet(slo.monitorLabels);
209
+
210
+ // SLOs without a label rule are curated by hand. Never touch them.
211
+ if (ruleLabelIds.size === 0) {
212
+ continue;
213
+ }
214
+
215
+ const attachedMonitorIds: Set<string> = toIdSet(slo.monitors);
216
+ const autoAddedMonitorIds: Set<string> = toIdSet(slo.autoAddedMonitors);
217
+
218
+ const doesMatch: boolean = this.doesLabelSetMatchRule({
219
+ labelIds: monitorLabelIds,
220
+ ruleLabelIds: ruleLabelIds,
221
+ });
222
+
223
+ /*
224
+ * Only this monitor's membership is in question, so the "matched" set
225
+ * handed to writeMembership is the SLO's current auto-added set with
226
+ * this monitor toggled in or out. Every other auto-added monitor is
227
+ * reported as still matching and is left exactly where it is.
228
+ */
229
+ const matchedMonitorIds: Set<string> = new Set<string>(
230
+ autoAddedMonitorIds,
231
+ );
232
+
233
+ if (doesMatch) {
234
+ matchedMonitorIds.add(monitorId);
235
+ } else {
236
+ matchedMonitorIds.delete(monitorId);
237
+ }
238
+
239
+ try {
240
+ const result: SloMonitorSyncResult = await this.writeMembership({
241
+ slo: slo,
242
+ attachedMonitorIds: attachedMonitorIds,
243
+ autoAddedMonitorIds: autoAddedMonitorIds,
244
+ matchedMonitorIds: matchedMonitorIds,
245
+ });
246
+
247
+ if (
248
+ result.monitorIdsAdded.length > 0 ||
249
+ result.monitorIdsRemoved.length > 0
250
+ ) {
251
+ results.push(result);
252
+ }
253
+ } catch (error) {
254
+ /*
255
+ * One SLO failing must not stop the others: the monitor's labels have
256
+ * already changed, and half a sync is better than none.
257
+ */
258
+ logger.error(
259
+ `Error syncing SLO ${slo.id?.toString()} for monitor ${monitorId}: ${error}`,
260
+ {
261
+ projectId: projectId.toString(),
262
+ monitorId: monitorId,
263
+ } as LogAttributes,
264
+ );
265
+ }
266
+ }
267
+
268
+ return results;
269
+ }
270
+
271
+ /**
272
+ * Every monitor in the project carrying at least one of `labelIds`.
273
+ */
274
+ @CaptureSpan()
275
+ private async findMonitorIdsWithAnyLabel(data: {
276
+ projectId: ObjectID;
277
+ labelIds: Set<string>;
278
+ }): Promise<Set<string>> {
279
+ const labelIds: Array<ObjectID> = Array.from(data.labelIds).map(
280
+ (id: string) => {
281
+ return new ObjectID(id);
282
+ },
283
+ );
284
+
285
+ if (labelIds.length === 0) {
286
+ return new Set<string>();
287
+ }
288
+
289
+ const monitors: Array<Monitor> = await MonitorService.findBy({
290
+ query: {
291
+ projectId: data.projectId,
292
+ labels: labelIds,
293
+ },
294
+ select: {
295
+ _id: true,
296
+ },
297
+ limit: LIMIT_PER_PROJECT,
298
+ skip: 0,
299
+ props: {
300
+ isRoot: true,
301
+ },
302
+ });
303
+
304
+ return toIdSet(monitors);
305
+ }
306
+
307
+ public doesLabelSetMatchRule(data: {
308
+ labelIds: Set<string>;
309
+ ruleLabelIds: Set<string>;
310
+ }): boolean {
311
+ if (data.ruleLabelIds.size === 0 || data.labelIds.size === 0) {
312
+ return false;
313
+ }
314
+
315
+ for (const labelId of data.labelIds) {
316
+ if (data.ruleLabelIds.has(labelId)) {
317
+ return true;
318
+ }
319
+ }
320
+
321
+ return false;
322
+ }
323
+
324
+ /**
325
+ * Applies a computed match set to one SLO and persists the difference.
326
+ *
327
+ * `matchedMonitorIds` is the full set of monitors the rule claims. Anything
328
+ * in it that is not attached gets attached and recorded as rule-owned;
329
+ * anything recorded as rule-owned that the rule no longer claims gets
330
+ * detached. Attachments that are not rule-owned are invisible to both
331
+ * halves, which is what keeps manual monitors safe.
332
+ */
333
+ private async writeMembership(data: {
334
+ slo: ServiceLevelObjective;
335
+ attachedMonitorIds: Set<string>;
336
+ autoAddedMonitorIds: Set<string>;
337
+ matchedMonitorIds: Set<string>;
338
+ }): Promise<SloMonitorSyncResult> {
339
+ const { slo, attachedMonitorIds, autoAddedMonitorIds, matchedMonitorIds } =
340
+ data;
341
+
342
+ if (!slo.id) {
343
+ return emptyResult();
344
+ }
345
+
346
+ const monitorIdsAdded: Array<string> = Array.from(matchedMonitorIds).filter(
347
+ (id: string) => {
348
+ return !attachedMonitorIds.has(id);
349
+ },
350
+ );
351
+
352
+ const monitorIdsRemoved: Array<string> = Array.from(
353
+ autoAddedMonitorIds,
354
+ ).filter((id: string) => {
355
+ return !matchedMonitorIds.has(id);
356
+ });
357
+
358
+ /*
359
+ * A monitor the rule still matches but that a human attached by hand stays
360
+ * manual: it is never promoted into autoAddedMonitors, so dropping the
361
+ * label later detaches nothing.
362
+ */
363
+ const nextAutoAddedMonitorIds: Set<string> = new Set<string>(
364
+ Array.from(autoAddedMonitorIds).filter((id: string) => {
365
+ return matchedMonitorIds.has(id);
366
+ }),
367
+ );
368
+
369
+ for (const id of monitorIdsAdded) {
370
+ nextAutoAddedMonitorIds.add(id);
371
+ }
372
+
373
+ const nextAttachedMonitorIds: Set<string> = new Set<string>(
374
+ Array.from(attachedMonitorIds).filter((id: string) => {
375
+ return !monitorIdsRemoved.includes(id);
376
+ }),
377
+ );
378
+
379
+ for (const id of monitorIdsAdded) {
380
+ nextAttachedMonitorIds.add(id);
381
+ }
382
+
383
+ /*
384
+ * Nothing to write. Checked against both sets rather than against
385
+ * added/removed alone, because a repair can leave the monitor list
386
+ * untouched while still needing to fix the auto-added bookkeeping.
387
+ */
388
+ if (
389
+ isSameSet(nextAttachedMonitorIds, attachedMonitorIds) &&
390
+ isSameSet(nextAutoAddedMonitorIds, autoAddedMonitorIds)
391
+ ) {
392
+ return emptyResult();
393
+ }
394
+
395
+ /*
396
+ * Cast through unknown: PartialEntity is a deep mapped type, and letting
397
+ * the compiler infer it for two arrays of Monitor (whose own relations
398
+ * fan out across most of the schema) trips TS2589 "type instantiation is
399
+ * excessively deep". The shape is exactly what the column types say.
400
+ */
401
+ const updateData: PartialEntity<ServiceLevelObjective> = {
402
+ monitors: toMonitors(nextAttachedMonitorIds),
403
+ autoAddedMonitors: toMonitors(nextAutoAddedMonitorIds),
404
+ } as unknown as PartialEntity<ServiceLevelObjective>;
405
+
406
+ await ServiceLevelObjectiveService.updateOneById({
407
+ id: slo.id,
408
+ data: updateData,
409
+ props: {
410
+ isRoot: true,
411
+ },
412
+ });
413
+
414
+ logger.debug(
415
+ `SLO monitor label rule synced SLO ${slo.id.toString()}: +${monitorIdsAdded.length} / -${monitorIdsRemoved.length} monitors`,
416
+ { projectId: slo.projectId?.toString() } as LogAttributes,
417
+ );
418
+
419
+ return {
420
+ monitorIdsAdded: monitorIdsAdded,
421
+ monitorIdsRemoved: monitorIdsRemoved,
422
+ };
423
+ }
424
+ }
425
+
426
+ export default new ServiceLevelObjectiveMonitorRuleEngineServiceClass();
@@ -25,6 +25,7 @@ import DatabaseService from "./DatabaseService";
25
25
  import MonitorStatusService from "./MonitorStatusService";
26
26
  import ProjectService from "./ProjectService";
27
27
  import ServiceLevelObjectiveBurnRateRuleService from "./ServiceLevelObjectiveBurnRateRuleService";
28
+ import ServiceLevelObjectiveMonitorRuleEngineService from "./ServiceLevelObjectiveMonitorRuleEngineService";
28
29
  import ServiceLevelObjectiveOwnerTeamService from "./ServiceLevelObjectiveOwnerTeamService";
29
30
  import ServiceLevelObjectiveOwnerUserService from "./ServiceLevelObjectiveOwnerUserService";
30
31
  import TeamMemberService from "./TeamMemberService";
@@ -156,6 +157,22 @@ export class Service extends DatabaseService<Model> {
156
157
  );
157
158
  }
158
159
 
160
+ /*
161
+ * An SLO created with a label rule must already carry the monitors that
162
+ * rule matches — otherwise it reads "no monitors attached, cannot be
163
+ * evaluated" until someone happens to edit a monitor.
164
+ */
165
+ try {
166
+ await ServiceLevelObjectiveMonitorRuleEngineService.syncMonitorsForSlo({
167
+ serviceLevelObjectiveId: createdItem.id!,
168
+ });
169
+ } catch (err) {
170
+ logger.error(
171
+ `Error applying the monitor label rule for SLO ${createdItem.id?.toString()}: ${err}`,
172
+ { projectId: createdItem.projectId?.toString() } as LogAttributes,
173
+ );
174
+ }
175
+
159
176
  return createdItem;
160
177
  }
161
178
 
@@ -237,6 +254,28 @@ export class Service extends DatabaseService<Model> {
237
254
  }
238
255
  }
239
256
 
257
+ /*
258
+ * The label rule changed, so the monitor set it implies changed with it.
259
+ * Re-run it before the re-evaluation stamp below: the sync writes
260
+ * `monitors`, which goes through this same hook and stamps
261
+ * nextEvaluationAt itself once the new set is persisted.
262
+ */
263
+ if (onUpdate.updateBy.data.monitorLabels !== undefined) {
264
+ for (const updatedItemId of updatedItemIds) {
265
+ try {
266
+ await ServiceLevelObjectiveMonitorRuleEngineService.syncMonitorsForSlo(
267
+ {
268
+ serviceLevelObjectiveId: updatedItemId,
269
+ },
270
+ );
271
+ } catch (err) {
272
+ logger.error(
273
+ `Error applying the monitor label rule for SLO ${updatedItemId.toString()}: ${err}`,
274
+ );
275
+ }
276
+ }
277
+ }
278
+
240
279
  /*
241
280
  * If the objective's math inputs changed, force a re-evaluation on the
242
281
  * worker's next tick.