@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
@@ -1,9 +1,14 @@
1
1
  import DatabaseService from "./DatabaseService";
2
2
  import Model from "../../Models/DatabaseModels/DockerResource";
3
3
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
4
+ import ColumnLength from "../../Types/Database/ColumnLength";
4
5
  import ObjectID from "../../Types/ObjectID";
5
6
  import OneUptimeDate from "../../Types/Date";
6
7
  import { JSONObject } from "../../Types/JSON";
8
+ import {
9
+ truncateLongText,
10
+ truncateShortText,
11
+ } from "../Utils/Database/TruncateColumnValue";
7
12
  import logger from "../Utils/Logger";
8
13
 
9
14
  /*
@@ -56,6 +61,35 @@ export interface DockerHostInventoryCounts {
56
61
  const UPSERT_BATCH_SIZE: number = 500;
57
62
  const STALE_DELETE_WARN_THRESHOLD: number = 100;
58
63
 
64
+ /*
65
+ * DockerResource's text columns are bounded varchars — name / imageName
66
+ * at 500 chars, kind / containerId / state at 100. These bulk paths go
67
+ * through manager.query(), which skips the length validation
68
+ * DatabaseService applies to ordinary writes, so a single oversized
69
+ * value aborts the whole 500-row INSERT chunk it rides in. Clamp per
70
+ * value instead, so one pathological container can never drop the rest.
71
+ */
72
+ function sanitizeContainer(c: ParsedDockerContainer): ParsedDockerContainer {
73
+ return {
74
+ ...c,
75
+ containerName: truncateLongText(c.containerName),
76
+ containerId: truncateShortText(c.containerId),
77
+ imageName: truncateLongText(c.imageName),
78
+ state: truncateShortText(c.state),
79
+ };
80
+ }
81
+
82
+ function sanitizeResource(r: ParsedDockerResource): ParsedDockerResource {
83
+ return {
84
+ ...r,
85
+ kind: truncateShortText(r.kind),
86
+ name: truncateLongText(r.name),
87
+ containerId: truncateShortText(r.containerId),
88
+ imageName: truncateLongText(r.imageName),
89
+ state: truncateShortText(r.state),
90
+ };
91
+ }
92
+
59
93
  export class Service extends DatabaseService<Model> {
60
94
  public constructor() {
61
95
  super(Model);
@@ -83,12 +117,20 @@ export class Service extends DatabaseService<Model> {
83
117
  return;
84
118
  }
85
119
 
86
- for (
87
- let i: number = 0;
88
- i < data.containers.length;
89
- i += UPSERT_BATCH_SIZE
90
- ) {
91
- const chunk: Array<ParsedDockerContainer> = data.containers.slice(
120
+ const containers: Array<ParsedDockerContainer> = data.containers.map(
121
+ (c: ParsedDockerContainer) => {
122
+ const sanitized: ParsedDockerContainer = sanitizeContainer(c);
123
+ if (sanitized.containerName !== c.containerName) {
124
+ logger.warn(
125
+ `DockerResource container name exceeds ${ColumnLength.LongText} chars; truncated to "${sanitized.containerName}" (host ${data.dockerHostId.toString()}).`,
126
+ );
127
+ }
128
+ return sanitized;
129
+ },
130
+ );
131
+
132
+ for (let i: number = 0; i < containers.length; i += UPSERT_BATCH_SIZE) {
133
+ const chunk: Array<ParsedDockerContainer> = containers.slice(
92
134
  i,
93
135
  i + UPSERT_BATCH_SIZE,
94
136
  );
@@ -164,8 +206,20 @@ export class Service extends DatabaseService<Model> {
164
206
  return;
165
207
  }
166
208
 
167
- for (let i: number = 0; i < data.resources.length; i += UPSERT_BATCH_SIZE) {
168
- const chunk: Array<ParsedDockerResource> = data.resources.slice(
209
+ const resources: Array<ParsedDockerResource> = data.resources.map(
210
+ (r: ParsedDockerResource) => {
211
+ const sanitized: ParsedDockerResource = sanitizeResource(r);
212
+ if (sanitized.name !== r.name) {
213
+ logger.warn(
214
+ `DockerResource name exceeds ${ColumnLength.LongText} chars; truncated to "${sanitized.name}" (host ${data.dockerHostId.toString()}).`,
215
+ );
216
+ }
217
+ return sanitized;
218
+ },
219
+ );
220
+
221
+ for (let i: number = 0; i < resources.length; i += UPSERT_BATCH_SIZE) {
222
+ const chunk: Array<ParsedDockerResource> = resources.slice(
169
223
  i,
170
224
  i + UPSERT_BATCH_SIZE,
171
225
  );
@@ -5,6 +5,7 @@ import Model from "../../Models/DatabaseModels/DockerSwarmCluster";
5
5
  import Label from "../../Models/DatabaseModels/Label";
6
6
  import { OnCreate } from "../Types/Database/Hooks";
7
7
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
8
+ import ResourceHeartbeat from "../Utils/Telemetry/ResourceHeartbeat";
8
9
  import ObjectID from "../../Types/ObjectID";
9
10
  import QueryHelper from "../Types/Database/QueryHelper";
10
11
  import OneUptimeDate from "../../Types/Date";
@@ -182,7 +183,6 @@ export class Service extends DatabaseService<Model> {
182
183
  networkCount?: number | undefined;
183
184
  },
184
185
  ): Promise<void> {
185
- const cacheKey: string = clusterId.toString();
186
186
  const extrasFingerprint: string = crypto
187
187
  .createHash("sha1")
188
188
  .update(
@@ -202,83 +202,65 @@ export class Service extends DatabaseService<Model> {
202
202
  )
203
203
  .digest("hex");
204
204
 
205
- let cached: string | null = null;
206
- try {
207
- cached = await GlobalCache.getString(LAST_SEEN_CACHE_NAMESPACE, cacheKey);
208
- } catch {
209
- /*
210
- * Cache unavailable — fail open and refresh lastSeenAt anyway. A
211
- * cache error must never skip the DB write below, otherwise the
212
- * resource is wrongly marked "disconnected" while telemetry is
213
- * still flowing. Mirrors shouldRunMaintenance's fail-open stance.
214
- */
215
- cached = null;
216
- }
217
-
218
- if (cached === extrasFingerprint) {
219
- return; // same data was written recently
220
- }
221
-
222
- try {
223
- await GlobalCache.setString(
224
- LAST_SEEN_CACHE_NAMESPACE,
225
- cacheKey,
226
- extrasFingerprint,
227
- { expiresInSeconds: LAST_SEEN_THROTTLE_SECONDS },
228
- );
229
- } catch {
230
- // Best-effort throttle write; proceed with the DB update regardless.
231
- }
232
-
233
205
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
234
- const data: any = {
206
+ const liveness: any = {
235
207
  lastSeenAt: OneUptimeDate.getCurrentDate(),
236
208
  otelCollectorStatus: "connected",
237
209
  };
238
210
 
211
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
212
+ const metadata: any = {};
213
+
239
214
  if (extra?.dockerVersion) {
240
- data.dockerVersion = extra.dockerVersion;
215
+ metadata.dockerVersion = extra.dockerVersion;
241
216
  }
242
217
  if (extra?.swarmId) {
243
- data.swarmId = extra.swarmId;
218
+ metadata.swarmId = extra.swarmId;
244
219
  }
245
220
  if (extra?.agentVersion) {
246
- data.agentVersion = extra.agentVersion;
221
+ metadata.agentVersion = extra.agentVersion;
247
222
  }
248
223
  // Counts: 0 is a legitimate value — gate on undefined, not falsiness.
249
224
  if (extra?.nodeCount !== undefined) {
250
- data.nodeCount = extra.nodeCount;
225
+ metadata.nodeCount = extra.nodeCount;
251
226
  }
252
227
  if (extra?.readyNodeCount !== undefined) {
253
- data.readyNodeCount = extra.readyNodeCount;
228
+ metadata.readyNodeCount = extra.readyNodeCount;
254
229
  }
255
230
  if (extra?.managerNodeCount !== undefined) {
256
- data.managerNodeCount = extra.managerNodeCount;
231
+ metadata.managerNodeCount = extra.managerNodeCount;
257
232
  }
258
233
  if (extra?.serviceCount !== undefined) {
259
- data.serviceCount = extra.serviceCount;
234
+ metadata.serviceCount = extra.serviceCount;
260
235
  }
261
236
  if (extra?.taskCount !== undefined) {
262
- data.taskCount = extra.taskCount;
237
+ metadata.taskCount = extra.taskCount;
263
238
  }
264
239
  if (extra?.runningTaskCount !== undefined) {
265
- data.runningTaskCount = extra.runningTaskCount;
240
+ metadata.runningTaskCount = extra.runningTaskCount;
266
241
  }
267
242
  if (extra?.stackCount !== undefined) {
268
- data.stackCount = extra.stackCount;
243
+ metadata.stackCount = extra.stackCount;
269
244
  }
270
245
  if (extra?.networkCount !== undefined) {
271
- data.networkCount = extra.networkCount;
246
+ metadata.networkCount = extra.networkCount;
272
247
  }
273
248
 
274
249
  /*
275
- * Heartbeat write: a single-statement UPDATE with no hooks and no
276
- * `version` bump, avoiding the hot-row Postgres lock convoy that the
277
- * full updateOneById pipeline causes. See ServiceService.updateLastSeen.
250
+ * One gated, non-blocking heartbeat write. The gates, the fail-open /
251
+ * fail-closed split and the liveness-only fallback all live in
252
+ * ResourceHeartbeat see there for why this row's throttle used to
253
+ * provide no throttling at all.
278
254
  */
279
- await this.updateColumnsByIdWithoutHooks({
255
+ await ResourceHeartbeat.write({
256
+ service: this,
280
257
  id: clusterId,
281
- data: data,
258
+ cacheNamespace: LAST_SEEN_CACHE_NAMESPACE,
259
+ throttleInSeconds: LAST_SEEN_THROTTLE_SECONDS,
260
+ liveness: liveness,
261
+ metadata: metadata,
262
+ fingerprint: extrasFingerprint,
263
+ describe: `docker swarm cluster ${clusterId.toString()}`,
282
264
  });
283
265
  }
284
266
 
@@ -1,9 +1,14 @@
1
1
  import DatabaseService from "./DatabaseService";
2
2
  import Model from "../../Models/DatabaseModels/DockerSwarmResource";
3
3
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
4
+ import ColumnLength from "../../Types/Database/ColumnLength";
4
5
  import ObjectID from "../../Types/ObjectID";
5
6
  import OneUptimeDate from "../../Types/Date";
6
7
  import { JSONObject } from "../../Types/JSON";
8
+ import {
9
+ truncateLongText,
10
+ truncateShortText,
11
+ } from "../Utils/Database/TruncateColumnValue";
7
12
  import logger from "../Utils/Logger";
8
13
 
9
14
  /*
@@ -95,6 +100,33 @@ const UPSERT_COLUMNS: Array<string> = [
95
100
  "version",
96
101
  ];
97
102
 
103
+ /*
104
+ * DockerSwarmResource's text columns are bounded varchars — image at
105
+ * 500 chars, everything else at 100. The bulk paths below go through
106
+ * manager.query(), which skips the length validation DatabaseService
107
+ * applies to ordinary writes, so a single oversized value aborts the
108
+ * whole 500-row INSERT chunk it rides in. Clamp per value instead, so
109
+ * one pathological task can never drop the rest of the snapshot.
110
+ */
111
+ function sanitizeResource(
112
+ r: ParsedDockerSwarmResource,
113
+ ): ParsedDockerSwarmResource {
114
+ return {
115
+ ...r,
116
+ kind: truncateShortText(r.kind),
117
+ externalId: truncateShortText(r.externalId),
118
+ name: truncateShortText(r.name),
119
+ state: truncateShortText(r.state),
120
+ role: truncateShortText(r.role),
121
+ serviceMode: truncateShortText(r.serviceMode),
122
+ image: truncateLongText(r.image),
123
+ stackName: truncateShortText(r.stackName),
124
+ serviceName: truncateShortText(r.serviceName),
125
+ nodeHostname: truncateShortText(r.nodeHostname),
126
+ driver: truncateShortText(r.driver),
127
+ };
128
+ }
129
+
98
130
  export class Service extends DatabaseService<Model> {
99
131
  public constructor() {
100
132
  super(Model);
@@ -120,8 +152,20 @@ export class Service extends DatabaseService<Model> {
120
152
  return;
121
153
  }
122
154
 
123
- for (let i: number = 0; i < data.resources.length; i += UPSERT_BATCH_SIZE) {
124
- const chunk: Array<ParsedDockerSwarmResource> = data.resources.slice(
155
+ const resources: Array<ParsedDockerSwarmResource> = data.resources.map(
156
+ (r: ParsedDockerSwarmResource) => {
157
+ const sanitized: ParsedDockerSwarmResource = sanitizeResource(r);
158
+ if (sanitized.externalId !== r.externalId) {
159
+ logger.warn(
160
+ `DockerSwarmResource externalId exceeds ${ColumnLength.ShortText} chars; truncated to "${sanitized.externalId}" (cluster ${data.dockerSwarmClusterId.toString()}).`,
161
+ );
162
+ }
163
+ return sanitized;
164
+ },
165
+ );
166
+
167
+ for (let i: number = 0; i < resources.length; i += UPSERT_BATCH_SIZE) {
168
+ const chunk: Array<ParsedDockerSwarmResource> = resources.slice(
125
169
  i,
126
170
  i + UPSERT_BATCH_SIZE,
127
171
  );
@@ -231,9 +275,14 @@ export class Service extends DatabaseService<Model> {
231
275
  valueFragments.push(
232
276
  `($${paramIndex++}, $${paramIndex++}, $${paramIndex++}::numeric, $${paramIndex++}::bigint, $${paramIndex++}::bigint, $${paramIndex++}::numeric, $${paramIndex++}::timestamptz)`,
233
277
  );
278
+ /*
279
+ * The identity clamps MUST match bulkUpsert's, or this mirror
280
+ * UPDATE would silently miss the row the upsert just wrote
281
+ * under the truncated externalId.
282
+ */
234
283
  params.push(
235
- m.kind,
236
- m.externalId,
284
+ truncateShortText(m.kind),
285
+ truncateShortText(m.externalId),
237
286
  m.cpuPercent !== null && m.cpuPercent !== undefined
238
287
  ? m.cpuPercent
239
288
  : null,
@@ -5,6 +5,7 @@ import Model from "../../Models/DatabaseModels/Host";
5
5
  import Label from "../../Models/DatabaseModels/Label";
6
6
  import { OnCreate } from "../Types/Database/Hooks";
7
7
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
8
+ import ResourceHeartbeat from "../Utils/Telemetry/ResourceHeartbeat";
8
9
  import ObjectID from "../../Types/ObjectID";
9
10
  import QueryHelper from "../Types/Database/QueryHelper";
10
11
  import OneUptimeDate from "../../Types/Date";
@@ -212,111 +213,93 @@ export class Service extends DatabaseService<Model> {
212
213
  * once per throttle window. If any extra value changed (e.g. cpuCores
213
214
  * updated, IP address changed), bust the cache and write immediately.
214
215
  */
215
- const cacheKey: string = hostId.toString();
216
216
  const extrasFingerprint: string = this.fingerprintExtras(extra);
217
- let cached: string | null = null;
218
- try {
219
- cached = await GlobalCache.getString(LAST_SEEN_CACHE_NAMESPACE, cacheKey);
220
- } catch {
221
- /*
222
- * Cache unavailable — fail open and refresh lastSeenAt anyway. A
223
- * cache error must never skip the DB write below, otherwise the
224
- * resource is wrongly marked "disconnected" while telemetry is
225
- * still flowing. Mirrors shouldRunMaintenance's fail-open stance.
226
- */
227
- cached = null;
228
- }
229
-
230
- if (cached === extrasFingerprint) {
231
- return; // same data was written recently
232
- }
233
-
234
- try {
235
- await GlobalCache.setString(
236
- LAST_SEEN_CACHE_NAMESPACE,
237
- cacheKey,
238
- extrasFingerprint,
239
- { expiresInSeconds: LAST_SEEN_THROTTLE_SECONDS },
240
- );
241
- } catch {
242
- // Best-effort throttle write; proceed with the DB update regardless.
243
- }
244
217
 
245
218
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
246
- const data: any = {
219
+ const liveness: any = {
247
220
  lastSeenAt: OneUptimeDate.getCurrentDate(),
248
221
  otelCollectorStatus: "connected",
249
222
  };
250
223
 
224
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
225
+ const metadata: any = {};
226
+
251
227
  if (extra?.osType) {
252
- data.osType = extra.osType;
228
+ metadata.osType = extra.osType;
253
229
  }
254
230
  if (extra?.osVersion) {
255
- data.osVersion = extra.osVersion;
231
+ metadata.osVersion = extra.osVersion;
256
232
  }
257
233
  if (extra?.hostId) {
258
- data.hostId = extra.hostId;
234
+ metadata.hostId = extra.hostId;
259
235
  }
260
236
  if (extra?.hostArch) {
261
- data.hostArch = extra.hostArch;
237
+ metadata.hostArch = extra.hostArch;
262
238
  }
263
239
  if (extra?.hostType) {
264
- data.hostType = extra.hostType;
240
+ metadata.hostType = extra.hostType;
265
241
  }
266
242
  if (extra?.hostIpAddresses) {
267
- data.hostIpAddresses = extra.hostIpAddresses;
243
+ metadata.hostIpAddresses = extra.hostIpAddresses;
268
244
  }
269
245
  if (extra?.cpuCores !== undefined) {
270
- data.cpuCores = extra.cpuCores;
246
+ metadata.cpuCores = extra.cpuCores;
271
247
  }
272
248
  if (extra?.totalMemoryBytes !== undefined) {
273
- data.totalMemoryBytes = extra.totalMemoryBytes;
249
+ metadata.totalMemoryBytes = extra.totalMemoryBytes;
274
250
  }
275
251
  if (extra?.processCount !== undefined) {
276
- data.processCount = extra.processCount;
252
+ metadata.processCount = extra.processCount;
277
253
  }
278
254
  if (extra?.containerRuntime) {
279
- data.containerRuntime = extra.containerRuntime;
255
+ metadata.containerRuntime = extra.containerRuntime;
280
256
  }
281
257
  if (extra?.dockerHostId) {
282
- data.dockerHostId = extra.dockerHostId;
258
+ metadata.dockerHostId = extra.dockerHostId;
283
259
  }
284
260
  if (extra?.kubernetesClusterId) {
285
- data.kubernetesClusterId = extra.kubernetesClusterId;
261
+ metadata.kubernetesClusterId = extra.kubernetesClusterId;
286
262
  }
287
263
  if (extra?.agentVersion) {
288
- data.agentVersion = extra.agentVersion;
264
+ metadata.agentVersion = extra.agentVersion;
289
265
  }
290
266
  if (extra?.deploymentEnvironment) {
291
- data.deploymentEnvironment = extra.deploymentEnvironment;
267
+ metadata.deploymentEnvironment = extra.deploymentEnvironment;
292
268
  }
293
269
  if (extra?.runtimeName) {
294
- data.runtimeName = extra.runtimeName;
270
+ metadata.runtimeName = extra.runtimeName;
295
271
  }
296
272
  if (extra?.runtimeVersion) {
297
- data.runtimeVersion = extra.runtimeVersion;
273
+ metadata.runtimeVersion = extra.runtimeVersion;
298
274
  }
299
275
  if (extra?.cloudProvider) {
300
- data.cloudProvider = extra.cloudProvider;
276
+ metadata.cloudProvider = extra.cloudProvider;
301
277
  }
302
278
  if (extra?.cloudPlatform) {
303
- data.cloudPlatform = extra.cloudPlatform;
279
+ metadata.cloudPlatform = extra.cloudPlatform;
304
280
  }
305
281
  if (extra?.cloudRegion) {
306
- data.cloudRegion = extra.cloudRegion;
282
+ metadata.cloudRegion = extra.cloudRegion;
307
283
  }
308
284
  if (extra?.cloudAccountId) {
309
- data.cloudAccountId = extra.cloudAccountId;
285
+ metadata.cloudAccountId = extra.cloudAccountId;
310
286
  }
311
287
 
312
288
  /*
313
- * Heartbeat write: a single-statement UPDATE with no hooks and no
314
- * `version` bump, avoiding the hot-row Postgres lock convoy that the
315
- * full updateOneById pipeline causes. See ServiceService.updateLastSeen.
289
+ * One gated, non-blocking heartbeat write. The gates, the fail-open /
290
+ * fail-closed split and the liveness-only fallback all live in
291
+ * ResourceHeartbeat see there for why this row's throttle used to
292
+ * provide no throttling at all.
316
293
  */
317
- await this.updateColumnsByIdWithoutHooks({
294
+ await ResourceHeartbeat.write({
295
+ service: this,
318
296
  id: hostId,
319
- data: data,
297
+ cacheNamespace: LAST_SEEN_CACHE_NAMESPACE,
298
+ throttleInSeconds: LAST_SEEN_THROTTLE_SECONDS,
299
+ liveness: liveness,
300
+ metadata: metadata,
301
+ fingerprint: extrasFingerprint,
302
+ describe: `host ${hostId.toString()}`,
320
303
  });
321
304
  }
322
305
 
@@ -349,9 +332,16 @@ export class Service extends DatabaseService<Model> {
349
332
  hostArch: extra?.hostArch ?? null,
350
333
  hostType: extra?.hostType ?? null,
351
334
  hostIpAddresses: extra?.hostIpAddresses ?? null,
352
- cpuCores: extra?.cpuCores ?? null,
353
- totalMemoryBytes: extra?.totalMemoryBytes ?? null,
354
- processCount: extra?.processCount ?? null,
335
+ /*
336
+ * cpuCores / totalMemoryBytes / processCount are DELIBERATELY not
337
+ * hashed. They are per-scrape gauges, and `system.processes.count` in
338
+ * particular is partitioned by process.status and summed, so it changes
339
+ * on essentially every scrape. Hashing them made the throttle key differ
340
+ * every time and the 60s window never engaged — for exactly the hosts
341
+ * producing the most batches, which is the worst possible place to lose
342
+ * a throttle. The columns are still written; they simply ride along on
343
+ * whatever write the throttle admits rather than forcing one.
344
+ */
355
345
  containerRuntime: extra?.containerRuntime ?? null,
356
346
  dockerHostId: extra?.dockerHostId?.toString() ?? null,
357
347
  kubernetesClusterId: extra?.kubernetesClusterId?.toString() ?? null,
@@ -25,6 +25,7 @@ import IncidentStateTimeline from "../../Models/DatabaseModels/IncidentStateTime
25
25
  import IncidentMember from "../../Models/DatabaseModels/IncidentMember";
26
26
  import IncidentRole from "../../Models/DatabaseModels/IncidentRole";
27
27
  import { IsBillingEnabled } from "../EnvironmentConfig";
28
+ import ProjectScopedReferenceValidator from "../Utils/Database/ProjectScopedReferenceValidator";
28
29
  import logger, { LogAttributes } from "../Utils/Logger";
29
30
  import IncidentFeedService from "./IncidentFeedService";
30
31
  import AIIncidentPostmortemRunner from "../Utils/AI/SRE/IncidentPostmortemRunner";
@@ -128,6 +129,25 @@ export class Service extends DatabaseService<IncidentStateTimeline> {
128
129
  throw new BadDataException("incidentStateId is null");
129
130
  }
130
131
 
132
+ /*
133
+ * Same guard, same reason, as MonitorStatusTimelineService: an id that
134
+ * exists nowhere (or belongs to another project) used to reach Postgres
135
+ * and come back as a raw foreign key violation. The ordering check below
136
+ * does look the state up, but only when there IS a preceding row with an
137
+ * order, so the first timeline row for an incident went through unchecked.
138
+ */
139
+ await ProjectScopedReferenceValidator.validateReferencesBelongToProject({
140
+ projectId: createBy.props.tenantId || createBy.data.projectId,
141
+ subject: "incident state timeline",
142
+ references: [
143
+ {
144
+ modelName: "Incident State",
145
+ id: incidentStateId,
146
+ service: IncidentStateService,
147
+ },
148
+ ],
149
+ });
150
+
131
151
  // Execute queries for before and after states in parallel for better performance
132
152
  const [stateBeforeThis, stateAfterThis] = await Promise.all([
133
153
  this.findOneBy({
@@ -177,6 +177,7 @@ import StatusPageOwnerUserService from "./StatusPageOwnerUserService";
177
177
  import StatusPagePrivateUserService from "./StatusPagePrivateUserService";
178
178
  import StatusPagePrivateUserSessionService from "./StatusPagePrivateUserSessionService";
179
179
  import StatusPageResourceService from "./StatusPageResourceService";
180
+ import StatusPageMonitorRuleService from "./StatusPageMonitorRuleService";
180
181
  // Status Page
181
182
  import StatusPageService from "./StatusPageService";
182
183
  import StatusPageSsoService from "./StatusPageSsoService";
@@ -438,6 +439,7 @@ const services: Array<BaseService> = [
438
439
  StatusPagePrivateUserService,
439
440
  StatusPagePrivateUserSessionService,
440
441
  StatusPageResourceService,
442
+ StatusPageMonitorRuleService,
441
443
  StatusPageService,
442
444
  StatusPageSsoService,
443
445
  StatusPageOidcService,
@@ -5,6 +5,7 @@ import ColumnLength from "../../Types/Database/ColumnLength";
5
5
  import ObjectID from "../../Types/ObjectID";
6
6
  import OneUptimeDate from "../../Types/Date";
7
7
  import { clampIoTTimestamp } from "../Utils/Telemetry/IoTSnapshotScan";
8
+ import { truncateShortText } from "../Utils/Database/TruncateColumnValue";
8
9
  import logger from "../Utils/Logger";
9
10
 
10
11
  /*
@@ -59,23 +60,6 @@ export interface IoTInventorySummary {
59
60
  const UPSERT_BATCH_SIZE: number = 500;
60
61
  const STALE_DELETE_WARN_THRESHOLD: number = 100;
61
62
 
62
- /*
63
- * The identity/text columns are ShortText (100 chars). A single value
64
- * over the column limit fails the whole multi-row INSERT chunk it rides
65
- * in — truncate per value instead so one malformed device can never
66
- * drop the other rows of its chunk.
67
- */
68
- function truncateShortText(value: string): string;
69
- function truncateShortText(value: string | null): string | null;
70
- function truncateShortText(value: string | null): string | null {
71
- if (value === null) {
72
- return value;
73
- }
74
- return value.length > ColumnLength.ShortText
75
- ? value.substring(0, ColumnLength.ShortText)
76
- : value;
77
- }
78
-
79
63
  /*
80
64
  * Column order used by bulkUpsert() and its generated parameter tuples.
81
65
  * Keep this and the INSERT column list in perfect sync.
@@ -5,6 +5,7 @@ import Model from "../../Models/DatabaseModels/IoTFleet";
5
5
  import Label from "../../Models/DatabaseModels/Label";
6
6
  import { OnCreate } from "../Types/Database/Hooks";
7
7
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
8
+ import ResourceHeartbeat from "../Utils/Telemetry/ResourceHeartbeat";
8
9
  import ObjectID from "../../Types/ObjectID";
9
10
  import QueryHelper from "../Types/Database/QueryHelper";
10
11
  import OneUptimeDate from "../../Types/Date";
@@ -173,7 +174,6 @@ export class Service extends DatabaseService<Model> {
173
174
  onlineDeviceCount?: number | undefined;
174
175
  },
175
176
  ): Promise<void> {
176
- const cacheKey: string = fleetId.toString();
177
177
  const extrasFingerprint: string = crypto
178
178
  .createHash("sha1")
179
179
  .update(
@@ -185,59 +185,41 @@ export class Service extends DatabaseService<Model> {
185
185
  )
186
186
  .digest("hex");
187
187
 
188
- let cached: string | null = null;
189
- try {
190
- cached = await GlobalCache.getString(LAST_SEEN_CACHE_NAMESPACE, cacheKey);
191
- } catch {
192
- /*
193
- * Cache unavailable — fail open and refresh lastSeenAt anyway. A
194
- * cache error must never skip the DB write below, otherwise the
195
- * resource is wrongly marked "disconnected" while telemetry is
196
- * still flowing. Mirrors shouldRunMaintenance's fail-open stance.
197
- */
198
- cached = null;
199
- }
200
-
201
- if (cached === extrasFingerprint) {
202
- return; // same data was written recently
203
- }
204
-
205
- try {
206
- await GlobalCache.setString(
207
- LAST_SEEN_CACHE_NAMESPACE,
208
- cacheKey,
209
- extrasFingerprint,
210
- { expiresInSeconds: LAST_SEEN_THROTTLE_SECONDS },
211
- );
212
- } catch {
213
- // Best-effort throttle write; proceed with the DB update regardless.
214
- }
215
-
216
188
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
217
- const data: any = {
189
+ const liveness: any = {
218
190
  lastSeenAt: OneUptimeDate.getCurrentDate(),
219
191
  otelCollectorStatus: "connected",
220
192
  };
221
193
 
194
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
195
+ const metadata: any = {};
196
+
222
197
  if (extra?.agentVersion) {
223
- data.agentVersion = extra.agentVersion;
198
+ metadata.agentVersion = extra.agentVersion;
224
199
  }
225
200
  // Counts: 0 is a legitimate value — gate on undefined, not falsiness.
226
201
  if (extra?.deviceCount !== undefined) {
227
- data.deviceCount = extra.deviceCount;
202
+ metadata.deviceCount = extra.deviceCount;
228
203
  }
229
204
  if (extra?.onlineDeviceCount !== undefined) {
230
- data.onlineDeviceCount = extra.onlineDeviceCount;
205
+ metadata.onlineDeviceCount = extra.onlineDeviceCount;
231
206
  }
232
207
 
233
208
  /*
234
- * Heartbeat write: a single-statement UPDATE with no hooks and no
235
- * `version` bump, avoiding the hot-row Postgres lock convoy that the
236
- * full updateOneById pipeline causes. See ServiceService.updateLastSeen.
209
+ * One gated, non-blocking heartbeat write. The gates, the fail-open /
210
+ * fail-closed split and the liveness-only fallback all live in
211
+ * ResourceHeartbeat see there for why this row's throttle used to
212
+ * provide no throttling at all.
237
213
  */
238
- await this.updateColumnsByIdWithoutHooks({
214
+ await ResourceHeartbeat.write({
215
+ service: this,
239
216
  id: fleetId,
240
- data: data,
217
+ cacheNamespace: LAST_SEEN_CACHE_NAMESPACE,
218
+ throttleInSeconds: LAST_SEEN_THROTTLE_SECONDS,
219
+ liveness: liveness,
220
+ metadata: metadata,
221
+ fingerprint: extrasFingerprint,
222
+ describe: `iot fleet ${fleetId.toString()}`,
241
223
  });
242
224
  }
243
225