@oneuptime/common 12.0.2 → 12.0.4

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 (384) hide show
  1. package/Models/DatabaseModels/CephCluster.ts +14 -0
  2. package/Models/DatabaseModels/CodeRepository.ts +14 -6
  3. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
  4. package/Models/DatabaseModels/DockerHost.ts +14 -0
  5. package/Models/DatabaseModels/GlobalOidcProject.ts +18 -0
  6. package/Models/DatabaseModels/GlobalSsoProject.ts +18 -0
  7. package/Models/DatabaseModels/Index.ts +2 -0
  8. package/Models/DatabaseModels/IoTFleet.ts +14 -0
  9. package/Models/DatabaseModels/KubernetesCluster.ts +14 -0
  10. package/Models/DatabaseModels/LogDropFilter.ts +9 -20
  11. package/Models/DatabaseModels/NetworkDevice.ts +14 -0
  12. package/Models/DatabaseModels/NetworkInterface.ts +18 -0
  13. package/Models/DatabaseModels/Project.ts +16 -2
  14. package/Models/DatabaseModels/ProxmoxCluster.ts +14 -0
  15. package/Models/DatabaseModels/Service.ts +30 -0
  16. package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
  17. package/Models/DatabaseModels/StatusPagePrivateUser.ts +30 -0
  18. package/Models/DatabaseModels/StatusPageResource.ts +73 -0
  19. package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
  20. package/Models/DatabaseModels/User.ts +30 -0
  21. package/Server/API/AIAgentDataAPI.ts +31 -0
  22. package/Server/API/BaseAPI.ts +13 -2
  23. package/Server/API/DashboardAPI.ts +458 -12
  24. package/Server/API/GitHubAPI.ts +119 -283
  25. package/Server/API/UserAPI.ts +263 -1
  26. package/Server/EnvironmentConfig.ts +38 -4
  27. package/Server/Infrastructure/GlobalCache.ts +152 -0
  28. package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.ts +21 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.ts +68 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +100 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +214 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.ts +69 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
  36. package/Server/Services/AlertStateTimelineService.ts +20 -0
  37. package/Server/Services/AnalyticsDatabaseService.ts +72 -1
  38. package/Server/Services/CephClusterService.ts +26 -86
  39. package/Server/Services/CloudResourceService.ts +23 -83
  40. package/Server/Services/CodeRepositoryService.ts +105 -2
  41. package/Server/Services/DatabaseService.ts +296 -2
  42. package/Server/Services/DockerHostService.ts +19 -79
  43. package/Server/Services/DockerSwarmClusterService.ts +27 -88
  44. package/Server/Services/HostService.ts +46 -99
  45. package/Server/Services/IncidentStateTimelineService.ts +20 -0
  46. package/Server/Services/Index.ts +2 -0
  47. package/Server/Services/IoTFleetService.ts +19 -79
  48. package/Server/Services/KubernetesClusterService.ts +17 -78
  49. package/Server/Services/LabelService.ts +57 -10
  50. package/Server/Services/MetricTypeService.ts +84 -0
  51. package/Server/Services/MonitorService.ts +89 -14
  52. package/Server/Services/MonitorStatusTimelineService.ts +29 -0
  53. package/Server/Services/MonitorTemplateService.ts +65 -0
  54. package/Server/Services/OpenTelemetryIngestService.ts +230 -26
  55. package/Server/Services/PodmanHostService.ts +19 -79
  56. package/Server/Services/ProxmoxClusterService.ts +23 -83
  57. package/Server/Services/RumApplicationService.ts +19 -80
  58. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
  59. package/Server/Services/ServerlessFunctionService.ts +24 -85
  60. package/Server/Services/ServiceService.ts +299 -73
  61. package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
  62. package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
  63. package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
  64. package/Server/Services/TelemetryEntityService.ts +1 -0
  65. package/Server/Services/UserService.ts +184 -0
  66. package/Server/Utils/AI/Toolbox/CodeTools.ts +45 -4
  67. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +13 -0
  68. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +157 -4
  69. package/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.ts +130 -0
  70. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
  71. package/Server/Utils/Monitor/MonitorResource.ts +63 -36
  72. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
  73. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
  74. package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
  75. package/Server/Utils/PasswordHash.ts +306 -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/OverviewCustomFields.test.tsx +333 -0
  82. package/Tests/App/Dashboard/UserCustomFields.test.tsx +392 -0
  83. package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
  84. package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
  85. package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
  86. package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
  87. package/Tests/Server/API/AIAgentDataRepositoryToken.test.ts +381 -0
  88. package/Tests/Server/API/DashboardPublicAttributeValuesAPI.test.ts +943 -0
  89. package/Tests/Server/API/DashboardPublicMetricsAggregateAPI.test.ts +1296 -0
  90. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
  91. package/Tests/Server/API/DashboardPublicTemplatePayloads.test.ts +598 -0
  92. package/Tests/Server/API/GitHubAppInstallationBindingAPI.test.ts +539 -0
  93. package/Tests/Server/API/Helpers.ts +6 -1
  94. package/Tests/Server/API/UserProjectsAPI.test.ts +852 -0
  95. package/Tests/Server/Infrastructure/GlobalCache.test.ts +354 -0
  96. package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
  97. package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +215 -0
  98. package/Tests/Server/Services/AddPerUserPasswordSaltMigration.test.ts +178 -0
  99. package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +582 -0
  100. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +5 -0
  101. package/Tests/Server/Services/CodeRepositoryInstallationBinding.test.ts +305 -0
  102. package/Tests/Server/Services/CodeRepositoryResolutionBinding.test.ts +147 -0
  103. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +870 -0
  104. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
  105. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
  106. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +163 -15
  107. package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
  108. package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
  109. package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
  110. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +568 -0
  111. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +305 -56
  112. package/Tests/Server/Services/RestoreDroppedUniqueIndexesMigration.test.ts +386 -0
  113. package/Tests/Server/Services/RestoreServiceLowerNameIndexMigration.test.ts +240 -0
  114. package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -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/UserServiceFirstMasterAdminElection.test.ts +885 -0
  119. package/Tests/Server/Services/WidenHashedStringColumnsForScryptMigration.test.ts +220 -0
  120. package/Tests/Server/Utils/AI/CodeTools.test.ts +47 -1
  121. package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +10 -0
  122. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
  123. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +120 -0
  124. package/Tests/Server/Utils/CodeRepository/GitHubInstallationBinding.test.ts +292 -0
  125. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
  126. package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
  127. package/Tests/Server/Utils/GitHubInstallationOwnershipVerification.test.ts +340 -0
  128. package/Tests/Server/Utils/GitHubWebhookAndTreeCacheIsolation.test.ts +250 -0
  129. package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
  130. package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
  131. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
  132. package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
  133. package/Tests/Server/Utils/PasswordHash.test.ts +555 -0
  134. package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
  135. package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
  136. package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
  137. package/Tests/Types/Database/ColumnLength.test.ts +7 -1
  138. package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
  139. package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
  140. package/Tests/Types/Decimal.test.ts +37 -0
  141. package/Tests/Types/HashedStringPerUserSalt.test.ts +476 -0
  142. package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +293 -0
  143. package/Tests/Types/Monitor/HostAlertTemplates.test.ts +249 -0
  144. package/Tests/Types/Monitor/IotAlertTemplates.test.ts +320 -0
  145. package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +271 -0
  146. package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
  147. package/Tests/Types/Port.test.ts +38 -0
  148. package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +696 -0
  149. package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
  150. package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
  151. package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
  152. package/Tests/UI/Utils/UserProjectsModelAPI.test.ts +714 -0
  153. package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
  154. package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
  155. package/Tests/Utils/TeamMembersByProject.test.ts +655 -0
  156. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  157. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  158. package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
  159. package/Types/Dashboard/DashboardTemplates.ts +397 -0
  160. package/Types/Database/BigIntColumnTransformer.ts +74 -0
  161. package/Types/Database/ColumnLength.ts +9 -1
  162. package/Types/Database/DatabaseProperty.ts +26 -0
  163. package/Types/Database/NumericColumnValue.ts +128 -0
  164. package/Types/Database/TableColumn.ts +11 -0
  165. package/Types/Database/UnsynchronizedIndex.ts +48 -0
  166. package/Types/Decimal.ts +16 -4
  167. package/Types/HashedString.ts +139 -4
  168. package/Types/Permission.ts +48 -0
  169. package/Types/Port.ts +16 -4
  170. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +85 -11
  171. package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
  172. package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
  173. package/UI/Components/Navbar/NavBar.tsx +12 -2
  174. package/UI/Components/Navbar/NavBarMenuModal.tsx +19 -7
  175. package/UI/Utils/ModelAPI/UserProjectsModelAPI.ts +257 -0
  176. package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
  177. package/Utils/Dashboard/Components/Index.ts +7 -0
  178. package/Utils/TeamMembersByProject.ts +237 -0
  179. package/build/dist/Models/DatabaseModels/CephCluster.js +16 -1
  180. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  181. package/build/dist/Models/DatabaseModels/CodeRepository.js +14 -6
  182. package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
  183. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
  184. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  185. package/build/dist/Models/DatabaseModels/DockerHost.js +16 -1
  186. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  187. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +16 -1
  188. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  189. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +16 -1
  190. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  191. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  192. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  193. package/build/dist/Models/DatabaseModels/IoTFleet.js +16 -1
  194. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  195. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +16 -1
  196. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  197. package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
  198. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  199. package/build/dist/Models/DatabaseModels/NetworkDevice.js +16 -1
  200. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  201. package/build/dist/Models/DatabaseModels/NetworkInterface.js +16 -1
  202. package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
  203. package/build/dist/Models/DatabaseModels/Project.js +16 -2
  204. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  205. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +16 -1
  206. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  207. package/build/dist/Models/DatabaseModels/Service.js +28 -1
  208. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  209. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
  210. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
  211. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +32 -0
  212. package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
  213. package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
  214. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  215. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
  216. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/User.js +32 -0
  218. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  219. package/build/dist/Server/API/AIAgentDataAPI.js +21 -2
  220. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  221. package/build/dist/Server/API/BaseAPI.js +11 -1
  222. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  223. package/build/dist/Server/API/DashboardAPI.js +343 -10
  224. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  225. package/build/dist/Server/API/GitHubAPI.js +94 -167
  226. package/build/dist/Server/API/GitHubAPI.js.map +1 -1
  227. package/build/dist/Server/API/UserAPI.js +187 -2
  228. package/build/dist/Server/API/UserAPI.js.map +1 -1
  229. package/build/dist/Server/EnvironmentConfig.js +34 -4
  230. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  231. package/build/dist/Server/Infrastructure/GlobalCache.js +120 -0
  232. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  233. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
  234. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js +14 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js.map +1 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js +59 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js.map +1 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +93 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js.map +1 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js +101 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js.map +1 -0
  245. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js +66 -0
  246. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js.map +1 -0
  247. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
  248. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  249. package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
  250. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  251. package/build/dist/Server/Services/AnalyticsDatabaseService.js +57 -1
  252. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  253. package/build/dist/Server/Services/CephClusterService.js +26 -76
  254. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  255. package/build/dist/Server/Services/CloudResourceService.js +23 -73
  256. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  257. package/build/dist/Server/Services/CodeRepositoryService.js +90 -2
  258. package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -1
  259. package/build/dist/Server/Services/DatabaseService.js +246 -2
  260. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  261. package/build/dist/Server/Services/DockerHostService.js +19 -69
  262. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  263. package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -78
  264. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  265. package/build/dist/Server/Services/HostService.js +58 -102
  266. package/build/dist/Server/Services/HostService.js.map +1 -1
  267. package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
  268. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  269. package/build/dist/Server/Services/Index.js +2 -0
  270. package/build/dist/Server/Services/Index.js.map +1 -1
  271. package/build/dist/Server/Services/IoTFleetService.js +19 -69
  272. package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
  273. package/build/dist/Server/Services/KubernetesClusterService.js +17 -68
  274. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  275. package/build/dist/Server/Services/LabelService.js +42 -7
  276. package/build/dist/Server/Services/LabelService.js.map +1 -1
  277. package/build/dist/Server/Services/MetricTypeService.js +74 -0
  278. package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
  279. package/build/dist/Server/Services/MonitorService.js +81 -9
  280. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  281. package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
  282. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  283. package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
  284. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  285. package/build/dist/Server/Services/OpenTelemetryIngestService.js +155 -25
  286. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  287. package/build/dist/Server/Services/PodmanHostService.js +19 -69
  288. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  289. package/build/dist/Server/Services/ProxmoxClusterService.js +23 -73
  290. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  291. package/build/dist/Server/Services/RumApplicationService.js +19 -70
  292. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  293. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
  294. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  295. package/build/dist/Server/Services/ServerlessFunctionService.js +24 -75
  296. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  297. package/build/dist/Server/Services/ServiceService.js +236 -61
  298. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  299. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
  300. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
  301. package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
  302. package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
  303. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
  304. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
  305. package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
  306. package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
  307. package/build/dist/Server/Services/UserService.js +165 -0
  308. package/build/dist/Server/Services/UserService.js.map +1 -1
  309. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +31 -1
  310. package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -1
  311. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +13 -0
  312. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  313. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +126 -4
  314. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  315. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js +136 -0
  316. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js.map +1 -0
  317. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
  318. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  319. package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
  320. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  321. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
  322. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  323. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
  324. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
  325. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
  326. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
  327. package/build/dist/Server/Utils/PasswordHash.js +237 -0
  328. package/build/dist/Server/Utils/PasswordHash.js.map +1 -0
  329. package/build/dist/Server/Utils/SingleFlight.js +76 -0
  330. package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
  331. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
  332. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
  333. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
  334. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  335. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
  336. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
  337. package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
  338. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  339. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  340. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  341. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  342. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  343. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
  344. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
  345. package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
  346. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  347. package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
  348. package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
  349. package/build/dist/Types/Database/ColumnLength.js +9 -1
  350. package/build/dist/Types/Database/ColumnLength.js.map +1 -1
  351. package/build/dist/Types/Database/DatabaseProperty.js +25 -0
  352. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  353. package/build/dist/Types/Database/NumericColumnValue.js +97 -0
  354. package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
  355. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  356. package/build/dist/Types/Database/UnsynchronizedIndex.js +46 -0
  357. package/build/dist/Types/Database/UnsynchronizedIndex.js.map +1 -0
  358. package/build/dist/Types/Decimal.js +14 -3
  359. package/build/dist/Types/Decimal.js.map +1 -1
  360. package/build/dist/Types/HashedString.js +95 -5
  361. package/build/dist/Types/HashedString.js.map +1 -1
  362. package/build/dist/Types/Permission.js +42 -0
  363. package/build/dist/Types/Permission.js.map +1 -1
  364. package/build/dist/Types/Port.js +15 -5
  365. package/build/dist/Types/Port.js.map +1 -1
  366. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +51 -10
  367. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  368. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
  369. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
  370. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
  371. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
  372. package/build/dist/UI/Components/Navbar/NavBar.js +3 -1
  373. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  374. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +19 -7
  375. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  376. package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js +156 -0
  377. package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js.map +1 -0
  378. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
  379. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
  380. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  381. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  382. package/build/dist/Utils/TeamMembersByProject.js +145 -0
  383. package/build/dist/Utils/TeamMembersByProject.js.map +1 -0
  384. package/package.json +1 -1
@@ -3,6 +3,7 @@ import Query from "../../Types/Database/Query";
3
3
  import QueryHelper from "../../Types/Database/QueryHelper";
4
4
  import Select from "../../Types/Database/Select";
5
5
  import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
6
+ import Dictionary from "../../../Types/Dictionary";
6
7
  import BadDataException from "../../../Types/Exception/BadDataException";
7
8
  import ObjectID from "../../../Types/ObjectID";
8
9
  import DatabaseBaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
@@ -20,12 +21,23 @@ import DatabaseBaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/
20
21
  * FKs are ON DELETE NO ACTION, so Postgres raises 23503 and the API answers
21
22
  * "This item cannot be deleted because Incident records still reference it."
22
23
  *
23
- * The check below is deliberately narrow, for the same reason
24
- * MonitorStepsProjectValidator is: it only rejects an id that really is
25
- * another project's record. An id that matches no row at all is left alone
26
- * refusing it would block users from saving their way out of a record that
27
- * already references something deleted, and the not-null/foreign-key checks
28
- * report that case on their own.
24
+ * An id that matches NO row is rejected too (issue #3039). The REST API used to
25
+ * take any uuid for these columns; the write then either blew up deep inside
26
+ * Postgres as a raw 23503 (an opaque 500 rather than "you picked a bad id"), or
27
+ * for ids that live in a JSON blob with no foreign key behind it, like
28
+ * monitorSteps saved happily and only failed much later, inside the probe
29
+ * worker, as
30
+ * insert or update on table "MonitorStatusTimeline" violates foreign key
31
+ * constraint
32
+ * with nothing surfaced to the caller who typed the bad id.
33
+ *
34
+ * Rejecting a missing id is safe for the columns validated here because every
35
+ * one of them is a real foreign key and deletes in this codebase are hard
36
+ * deletes (DatabaseService._deleteBy), so a *stored* id can never dangle: the
37
+ * ON DELETE NO ACTION constraint blocks the delete while a row still points at
38
+ * it. A missing id therefore only ever comes from the payload being validated.
39
+ * Callers whose reference is NOT foreign-key backed (monitorSteps ids, say) can
40
+ * opt a single reference out with `mustExist: false`.
29
41
  */
30
42
 
31
43
  export interface ProjectScopedReference {
@@ -34,6 +46,13 @@ export interface ProjectScopedReference {
34
46
  id: ObjectID | string | undefined | null;
35
47
  // The service that owns the referenced model, e.g. IncidentSeverityService.
36
48
  service: DatabaseService<DatabaseBaseModel>;
49
+ /*
50
+ * Defaults to true: an id that matches no record is rejected. Set false for a
51
+ * reference that is allowed to dangle — one with no foreign key behind it,
52
+ * where refusing would block a user from saving their way out of a record
53
+ * that already points at something deleted.
54
+ */
55
+ mustExist?: boolean | undefined;
37
56
  }
38
57
 
39
58
  interface ForeignReference {
@@ -41,6 +60,33 @@ interface ForeignReference {
41
60
  name: string;
42
61
  }
43
62
 
63
+ interface MissingReference {
64
+ modelName: string;
65
+ id: string;
66
+ }
67
+
68
+ // What the caller asked about, keyed by id inside one service's lookup.
69
+ interface RequestedReference {
70
+ modelName: string;
71
+ mustExist: boolean;
72
+ // The id exactly as the caller wrote it, so the message echoes their input.
73
+ id: string;
74
+ }
75
+
76
+ /*
77
+ * Ids are matched case-insensitively.
78
+ *
79
+ * ObjectID keeps whatever case it was handed (its validation regex is
80
+ * case-insensitive) and Postgres compares `uuid` values by parsed value, so a
81
+ * payload carrying an UPPERCASE uuid selects the row fine — but reads the id
82
+ * back lower-cased, because that is how Postgres renders `uuid`. Comparing the
83
+ * two verbatim would find no match and report a record that plainly exists as
84
+ * missing.
85
+ */
86
+ function normalizeId(id: string): string {
87
+ return id.trim().toLowerCase();
88
+ }
89
+
44
90
  /*
45
91
  * The same reference reaches a service hook in several shapes: the id column
46
92
  * (`incidentSeverityId`), a relation object (`incidentSeverity: { _id }`), an
@@ -92,11 +138,11 @@ export default class ProjectScopedReferenceValidator {
92
138
  */
93
139
  const idsByService: Map<
94
140
  DatabaseService<DatabaseBaseModel>,
95
- Map<string, string>
141
+ Map<string, RequestedReference>
96
142
  > = new Map();
97
143
 
98
144
  for (const reference of data.references) {
99
- const id: string = reference.id?.toString() || "";
145
+ const id: string = reference.id?.toString().trim() || "";
100
146
 
101
147
  if (!id) {
102
148
  continue;
@@ -106,7 +152,25 @@ export default class ProjectScopedReferenceValidator {
106
152
  idsByService.set(reference.service, new Map());
107
153
  }
108
154
 
109
- idsByService.get(reference.service)!.set(id, reference.modelName);
155
+ const requested: Map<string, RequestedReference> = idsByService.get(
156
+ reference.service,
157
+ )!;
158
+
159
+ const key: string = normalizeId(id);
160
+
161
+ const existing: RequestedReference | undefined = requested.get(key);
162
+
163
+ requested.set(key, {
164
+ modelName: reference.modelName,
165
+ id: existing?.id || id,
166
+ /*
167
+ * The same id can arrive twice for one service (e.g. two monitor
168
+ * criteria pointing at the same status). If ANY of them requires the
169
+ * record to exist, the strictest wins.
170
+ */
171
+ mustExist:
172
+ (existing?.mustExist ?? false) || (reference.mustExist ?? true),
173
+ });
110
174
  }
111
175
 
112
176
  if (idsByService.size === 0) {
@@ -114,21 +178,38 @@ export default class ProjectScopedReferenceValidator {
114
178
  }
115
179
 
116
180
  const foreignReferences: Array<ForeignReference> = [];
181
+ const missingReferences: Array<MissingReference> = [];
182
+
183
+ for (const [service, requestedById] of idsByService) {
184
+ /*
185
+ * Read the tenant and name columns off the model rather than assuming
186
+ * `projectId` / `name`. Not every referenced model is project scoped —
187
+ * a monitor criteria can name owner *users*, and User has no tenant
188
+ * column at all. Selecting a column a model does not have throws, and
189
+ * comparing an absent projectId against the write's project would
190
+ * report every such record as belonging to "a different project".
191
+ */
192
+ const referencedModel: DatabaseBaseModel = service.getModel();
193
+ const tenantColumnName: string | null = referencedModel.getTenantColumn();
194
+ const hasNameColumn: boolean = referencedModel.hasColumn("name");
195
+
196
+ const select: Select<DatabaseBaseModel> = {
197
+ _id: true,
198
+ } as Select<DatabaseBaseModel>;
199
+
200
+ if (hasNameColumn) {
201
+ (select as Dictionary<boolean>)["name"] = true;
202
+ }
203
+
204
+ if (tenantColumnName) {
205
+ (select as Dictionary<boolean>)[tenantColumnName] = true;
206
+ }
117
207
 
118
- for (const [service, idToModelName] of idsByService) {
119
208
  const records: Array<DatabaseBaseModel> = await service.findBy({
120
209
  query: {
121
- _id: QueryHelper.any(Array.from(idToModelName.keys())),
210
+ _id: QueryHelper.any(Array.from(requestedById.keys())),
122
211
  },
123
- /*
124
- * `name` and `projectId` are not on DatabaseBaseModel, but every model
125
- * passed here is project scoped and named, so the cast is safe.
126
- */
127
- select: {
128
- _id: true,
129
- name: true,
130
- projectId: true,
131
- } as Select<DatabaseBaseModel>,
212
+ select: select,
132
213
  limit: LIMIT_PER_PROJECT,
133
214
  skip: 0,
134
215
  props: {
@@ -136,37 +217,84 @@ export default class ProjectScopedReferenceValidator {
136
217
  },
137
218
  });
138
219
 
220
+ const foundIds: Set<string> = new Set();
221
+
139
222
  for (const record of records) {
223
+ const id: string = normalizeId(record._id?.toString() || "");
224
+
225
+ foundIds.add(id);
226
+
227
+ if (!tenantColumnName) {
228
+ // Global record (e.g. User) — there is no project to compare against.
229
+ continue;
230
+ }
231
+
140
232
  const recordProjectId: ObjectID | undefined =
141
- record.getValue<ObjectID>("projectId") || undefined;
233
+ record.getValue<ObjectID>(tenantColumnName) || undefined;
142
234
 
143
235
  if (recordProjectId?.toString() === data.projectId.toString()) {
144
236
  continue;
145
237
  }
146
238
 
147
- const id: string = record._id?.toString() || "";
148
-
149
239
  foreignReferences.push({
150
- modelName: idToModelName.get(id) || "Record",
151
- name: record.getValue<string>("name")?.toString() || id,
240
+ modelName: requestedById.get(id)?.modelName || "Record",
241
+ name:
242
+ (hasNameColumn && record.getValue<string>("name")?.toString()) ||
243
+ id,
244
+ });
245
+ }
246
+
247
+ for (const [id, requested] of requestedById) {
248
+ if (foundIds.has(id) || !requested.mustExist) {
249
+ continue;
250
+ }
251
+
252
+ missingReferences.push({
253
+ modelName: requested.modelName,
254
+ // Echo the id as the caller wrote it, not the normalized key.
255
+ id: requested.id,
152
256
  });
153
257
  }
154
258
  }
155
259
 
156
- if (foreignReferences.length === 0) {
157
- return;
260
+ /*
261
+ * Both problems are reported in one go so a caller fixing a payload with
262
+ * several bad ids does not have to discover them one round-trip at a time.
263
+ * The wording of each clause is kept verbatim from when they were separate
264
+ * messages — support runbooks and tests match on it.
265
+ */
266
+ const clauses: Array<string> = [];
267
+
268
+ if (foreignReferences.length > 0) {
269
+ const described: string = foreignReferences
270
+ .map((reference: ForeignReference) => {
271
+ return `${reference.modelName} "${reference.name}"`;
272
+ })
273
+ .join(", ");
274
+
275
+ clauses.push(
276
+ `references records that belong to a different project: ${described}. Please pick values from this project and try again.`,
277
+ );
278
+ }
279
+
280
+ if (missingReferences.length > 0) {
281
+ const described: string = missingReferences
282
+ .map((reference: MissingReference) => {
283
+ return `${reference.modelName} "${reference.id}"`;
284
+ })
285
+ .join(", ");
286
+
287
+ clauses.push(
288
+ `references records that do not exist: ${described}. Please pick values that exist in this project and try again.`,
289
+ );
158
290
  }
159
291
 
160
- const described: string = foreignReferences
161
- .map((reference: ForeignReference) => {
162
- return `${reference.modelName} "${reference.name}"`;
163
- })
164
- .join(", ");
292
+ if (clauses.length === 0) {
293
+ return;
294
+ }
165
295
 
166
296
  throw new BadDataException(
167
- `This ${
168
- data.subject || "request"
169
- } references records that belong to a different project: ${described}. Please pick values from this project and try again.`,
297
+ `This ${data.subject || "request"} ${clauses.join(" It also ")}`,
170
298
  );
171
299
  }
172
300
 
@@ -178,10 +306,13 @@ export default class ProjectScopedReferenceValidator {
178
306
  * there fails the whole ingest job for that monitor, so those callers ask
179
307
  * this instead and fall back to their project's own default.
180
308
  *
181
- * Note the deliberate difference from validateReferencesBelongToProject: an
182
- * id that matches NO record is unusable here (false), while the write guard
183
- * lets it pass so a record already pointing at something deleted stays
184
- * saveable.
309
+ * Note the deliberate difference from validateReferencesBelongToProject:
310
+ * that one refuses the write and names what is wrong, which is right when
311
+ * someone is typing an id in. This one answers a question and never throws,
312
+ * which is right when a worker is reading an id that was typed in long ago —
313
+ * an id monitorSteps is allowed to keep holding (the write guard exempts what
314
+ * a record already stores, since none of those ids has a foreign key behind
315
+ * it and there is no migration to clean them up).
185
316
  */
186
317
  public static async isUsableInProject(data: {
187
318
  projectId: ObjectID | undefined;
@@ -50,6 +50,7 @@ import CaptureSpan from "../Telemetry/CaptureSpan";
50
50
  import ExceptionMessages from "../../../Types/Exception/ExceptionMessages";
51
51
  import MonitorEvaluationSummary from "../../../Types/Monitor/MonitorEvaluationSummary";
52
52
  import MonitorStatusService from "../../Services/MonitorStatusService";
53
+ import ProjectScopedReferenceValidator from "../Database/ProjectScopedReferenceValidator";
53
54
  import { ProbeConnectionStatus } from "../../../Models/DatabaseModels/Probe";
54
55
  import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
55
56
 
@@ -1063,48 +1064,74 @@ export default class MonitorResourceUtil {
1063
1064
  */
1064
1065
  let revertedToDefaultStatus: boolean = true;
1065
1066
 
1066
- try {
1067
- await MonitorStatusTimelineService.create({
1068
- data: monitorStatusTimeline,
1069
- props: {
1070
- isRoot: true,
1071
- },
1067
+ /*
1068
+ * The stored default status can be a status that no longer exists, or
1069
+ * one from another project: monitorSteps is a JSON blob with no
1070
+ * foreign key behind it, and before issue #3039 was fixed the API
1071
+ * accepted any uuid for it. Writing it raised the
1072
+ * "violates foreign key constraint" error from the probe/telemetry
1073
+ * worker and failed the whole ingest run for this monitor, losing the
1074
+ * monitor log and payload persisted below. Skip the revert and log,
1075
+ * the same way the criteria path in Utils/Monitor/MonitorStatusTimeline
1076
+ * does. New writes are rejected up front by
1077
+ * MonitorStepsProjectValidator.
1078
+ */
1079
+ const isDefaultStatusUsable: boolean =
1080
+ await ProjectScopedReferenceValidator.isUsableInProject({
1081
+ projectId: monitor.projectId!,
1082
+ id: monitorSteps.data.defaultMonitorStatusId,
1083
+ service: MonitorStatusService,
1072
1084
  });
1073
- logger.debug(
1074
- `${dataToProcess.monitorId.toString()} - Monitor status updated to default.`,
1085
+
1086
+ if (!isDefaultStatusUsable) {
1087
+ logger.error(
1088
+ `${dataToProcess.monitorId.toString()} - The default monitor status ${monitorSteps.data.defaultMonitorStatusId.toString()} does not exist in project ${monitor.projectId?.toString()}. Skipping revert to default status. Please pick a default monitor status that exists in this project.`,
1075
1089
  );
1076
- } catch (err) {
1077
- /*
1078
- * Idempotent concurrency race (see MonitorStatusTimeline.ts): a
1079
- * concurrent result already moved the monitor to this default status,
1080
- * so onBeforeCreate's dedupe check throws this exact BadDataException.
1081
- * Treat as a no-op at debug level rather than failing the job. Match the
1082
- * exact message so unrelated BadDataExceptions still propagate.
1083
- */
1084
- if (
1085
- err instanceof BadDataException &&
1086
- err.message === MONITOR_STATUS_SAME_AS_PREVIOUS_ERROR_MESSAGE
1087
- ) {
1090
+ revertedToDefaultStatus = false;
1091
+ } else {
1092
+ try {
1093
+ await MonitorStatusTimelineService.create({
1094
+ data: monitorStatusTimeline,
1095
+ props: {
1096
+ isRoot: true,
1097
+ },
1098
+ });
1088
1099
  logger.debug(
1089
- `${dataToProcess.monitorId.toString()} - Monitor status already at default; skipping duplicate status timeline (concurrent race).`,
1100
+ `${dataToProcess.monitorId.toString()} - Monitor status updated to default.`,
1090
1101
  );
1091
- } else if (
1092
- err instanceof ServerException &&
1093
- err.message === MONITOR_STATUS_TIMELINE_LOCK_ERROR_MESSAGE
1094
- ) {
1102
+ } catch (err) {
1095
1103
  /*
1096
- * The per-monitor timeline mutex could not be acquired (fail-closed
1097
- * create, see MonitorStatusTimelineService). Skipping is recoverable:
1098
- * the next probe result re-evaluates the same criteria and recreates
1099
- * the revert-to-default, while failing here would abort the whole
1100
- * ingest run and lose the monitor log for this probe result.
1104
+ * Idempotent concurrency race (see MonitorStatusTimeline.ts): a
1105
+ * concurrent result already moved the monitor to this default status,
1106
+ * so onBeforeCreate's dedupe check throws this exact BadDataException.
1107
+ * Treat as a no-op at debug level rather than failing the job. Match the
1108
+ * exact message so unrelated BadDataExceptions still propagate.
1101
1109
  */
1102
- logger.error(
1103
- `${dataToProcess.monitorId.toString()} - Could not acquire the monitor status timeline lock; skipping revert to default status. It will be retried on the next probe result.`,
1104
- );
1105
- revertedToDefaultStatus = false;
1106
- } else {
1107
- throw err;
1110
+ if (
1111
+ err instanceof BadDataException &&
1112
+ err.message === MONITOR_STATUS_SAME_AS_PREVIOUS_ERROR_MESSAGE
1113
+ ) {
1114
+ logger.debug(
1115
+ `${dataToProcess.monitorId.toString()} - Monitor status already at default; skipping duplicate status timeline (concurrent race).`,
1116
+ );
1117
+ } else if (
1118
+ err instanceof ServerException &&
1119
+ err.message === MONITOR_STATUS_TIMELINE_LOCK_ERROR_MESSAGE
1120
+ ) {
1121
+ /*
1122
+ * The per-monitor timeline mutex could not be acquired (fail-closed
1123
+ * create, see MonitorStatusTimelineService). Skipping is recoverable:
1124
+ * the next probe result re-evaluates the same criteria and recreates
1125
+ * the revert-to-default, while failing here would abort the whole
1126
+ * ingest run and lose the monitor log for this probe result.
1127
+ */
1128
+ logger.error(
1129
+ `${dataToProcess.monitorId.toString()} - Could not acquire the monitor status timeline lock; skipping revert to default status. It will be retried on the next probe result.`,
1130
+ );
1131
+ revertedToDefaultStatus = false;
1132
+ } else {
1133
+ throw err;
1134
+ }
1108
1135
  }
1109
1136
  }
1110
1137
 
@@ -9,7 +9,9 @@ import MonitorStatusTimelineService, {
9
9
  MONITOR_STATUS_SAME_AS_PREVIOUS_ERROR_MESSAGE,
10
10
  MONITOR_STATUS_TIMELINE_LOCK_ERROR_MESSAGE,
11
11
  } from "../../Services/MonitorStatusTimelineService";
12
+ import MonitorStatusService from "../../Services/MonitorStatusService";
12
13
  import ServerException from "../../../Types/Exception/ServerException";
14
+ import ProjectScopedReferenceValidator from "../Database/ProjectScopedReferenceValidator";
13
15
  import logger, { LogAttributes } from "../Logger";
14
16
  import CaptureSpan from "../Telemetry/CaptureSpan";
15
17
  import DataToProcess from "./DataToProcess";
@@ -112,6 +114,40 @@ export default class MonitorStatusTimelineUtil {
112
114
  throw new BadDataException("Monitor status is not defined.");
113
115
  }
114
116
 
117
+ /*
118
+ * The criteria can name a status that no longer exists, or that belongs to
119
+ * another project: monitorSteps is a JSON blob with no foreign key behind
120
+ * it, so deleting a monitor status does not rewrite the criteria that
121
+ * point at it, and before issue #3039 was fixed the API accepted any uuid
122
+ * here in the first place. Writing it anyway is what raised
123
+ * insert or update on table "MonitorStatusTimeline" violates foreign key
124
+ * constraint
125
+ * inside the probe/telemetry worker, failing the whole ingest run for this
126
+ * monitor - no status change, and no monitor log or payload persisted
127
+ * either, because those come after this. Skip the status change and log,
128
+ * the same way MonitorIncident and MonitorAlert handle an unusable
129
+ * severity. New writes are rejected up front by
130
+ * MonitorStepsProjectValidator, so this only ever fires for monitors saved
131
+ * before that guard existed.
132
+ */
133
+ const isMonitorStatusUsable: boolean =
134
+ await ProjectScopedReferenceValidator.isUsableInProject({
135
+ projectId: input.monitor.projectId!,
136
+ id: monitorStatusId,
137
+ service: MonitorStatusService,
138
+ });
139
+
140
+ if (!isMonitorStatusUsable) {
141
+ logger.error(
142
+ `${input.monitor.id?.toString()} - Criteria "${
143
+ input.criteriaInstance.data?.name
144
+ }" changes the monitor status to ${monitorStatusId.toString()}, which does not exist in project ${input.monitor.projectId?.toString()}. Skipping the status change. Please pick a monitor status that exists in this project.`,
145
+ monitorLogAttributes,
146
+ );
147
+
148
+ return null;
149
+ }
150
+
115
151
  //change monitor status.
116
152
 
117
153
  // get last status of this monitor.