@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
@@ -0,0 +1,724 @@
1
+ import MonitorStepsReferenceExtractor, {
2
+ MonitorStepsReference,
3
+ MonitorStepsReferenceModel,
4
+ toReferenceId,
5
+ } from "../../../../Server/Utils/Monitor/MonitorStepsReferenceExtractor";
6
+ import { JSONObject, JSONValue, ObjectType } from "../../../../Types/JSON";
7
+ import MonitorSteps from "../../../../Types/Monitor/MonitorSteps";
8
+ import ObjectID from "../../../../Types/ObjectID";
9
+ import { describe, expect, it } from "@jest/globals";
10
+
11
+ /*
12
+ * Contract under test: tell a real reference inside monitorSteps apart from the
13
+ * many uuids in there that are NOT references.
14
+ *
15
+ * This is the whole reason issue #3039 could not be fixed before. The old guard
16
+ * scraped every uuid out of the serialized blob with a regex, so it could only
17
+ * ever ask "does this happen to be another project's record?" — asking "does
18
+ * this exist?" would have rejected every step id, criteria id and
19
+ * incident/alert template id, none of which match a row anywhere.
20
+ *
21
+ * Reading the structure instead means every id that comes back is known to
22
+ * point at a specific model, so it can be required to exist.
23
+ */
24
+
25
+ const STATUS_ID: string = "0a3f7e0e-0a4a-4f3f-8b46-0f4f1e2d5c60";
26
+ const DEFAULT_STATUS_ID: string = "5e8b6bd1-3a09-4b0b-9a4e-2a76b0a1c111";
27
+ const INCIDENT_SEVERITY_ID: string = "9b1c1c1e-8a11-4a6f-9c31-6d2f0b6d4a22";
28
+ const ALERT_SEVERITY_ID: string = "c31b3a44-1f60-4a1d-95bb-3e0e6f9a7d33";
29
+ const ON_CALL_POLICY_ID: string = "d40e5c55-2b71-4b2e-86cc-4f1f7a0b8e44";
30
+ const LABEL_ID: string = "e51f6d66-3c82-4c3f-97dd-501a8b1c9f55";
31
+ const TEAM_ID: string = "f6207e77-4d93-4d40-a8ee-612b9c2daa66";
32
+ const USER_ID: string = "07318f88-5ea4-4e51-b9ff-723cad3ebb77";
33
+ const ROLE_ID: string = "1842909a-6fb5-4f62-8a00-834dbe4fcc88";
34
+ const TELEMETRY_SERVICE_ID: string = "29530aab-70c6-4073-9b11-945ecf50dd99";
35
+ const NETWORK_DEVICE_ID: string = "3a641bbc-81d7-4184-8c22-a56fd0610eaa";
36
+
37
+ // Local identity, not a pointer at another row. None of these may be returned.
38
+ const STEP_ID: string = "4b752ccd-92e8-4295-9d33-b670e1721fbb";
39
+ const CRITERIA_ID: string = "5c863dde-a3f9-43a6-8e44-c781f2832acc";
40
+ const INCIDENT_TEMPLATE_ID: string = "6d974eef-b40a-44b7-9f55-d892031943dd";
41
+ const ALERT_TEMPLATE_ID: string = "7ea85ff0-c51b-45c8-a066-e9a3142a54ee";
42
+
43
+ /*
44
+ * `{"_type":"ObjectID","value":"…"}` — how JSONFunctions.serialize writes the
45
+ * ObjectIDs nested inside the incidents and alerts arrays.
46
+ */
47
+ const objectIdJSON: (id: string) => JSONObject = (id: string): JSONObject => {
48
+ return { _type: ObjectType.ObjectID, value: id };
49
+ };
50
+
51
+ const criteriaInstance: (overrides: JSONObject) => JSONObject = (
52
+ overrides: JSONObject,
53
+ ): JSONObject => {
54
+ return {
55
+ _type: ObjectType.MonitorCriteriaInstance,
56
+ value: {
57
+ id: CRITERIA_ID,
58
+ name: "Monitor is offline",
59
+ description: "",
60
+ filterCondition: "all",
61
+ filters: [],
62
+ incidents: [],
63
+ alerts: [],
64
+ ...overrides,
65
+ },
66
+ };
67
+ };
68
+
69
+ const stepsWithCriteria: (
70
+ instances: Array<JSONObject>,
71
+ stepOverrides?: JSONObject,
72
+ ) => JSONObject = (
73
+ instances: Array<JSONObject>,
74
+ stepOverrides?: JSONObject,
75
+ ): JSONObject => {
76
+ return {
77
+ _type: ObjectType.MonitorSteps,
78
+ value: {
79
+ defaultMonitorStatusId: DEFAULT_STATUS_ID,
80
+ monitorStepsInstanceArray: [
81
+ {
82
+ _type: ObjectType.MonitorStep,
83
+ value: {
84
+ id: STEP_ID,
85
+ ...(stepOverrides || {}),
86
+ monitorCriteria: {
87
+ _type: ObjectType.MonitorCriteria,
88
+ value: {
89
+ monitorCriteriaInstanceArray: instances,
90
+ },
91
+ },
92
+ },
93
+ },
94
+ ],
95
+ },
96
+ };
97
+ };
98
+
99
+ const idsFor: (
100
+ references: Array<MonitorStepsReference>,
101
+ model: MonitorStepsReferenceModel,
102
+ ) => Array<string> = (
103
+ references: Array<MonitorStepsReference>,
104
+ model: MonitorStepsReferenceModel,
105
+ ): Array<string> => {
106
+ return references
107
+ .filter((reference: MonitorStepsReference) => {
108
+ return reference.model === model;
109
+ })
110
+ .map((reference: MonitorStepsReference) => {
111
+ return reference.id;
112
+ });
113
+ };
114
+
115
+ const findById: (
116
+ references: Array<MonitorStepsReference>,
117
+ id: string,
118
+ ) => MonitorStepsReference | undefined = (
119
+ references: Array<MonitorStepsReference>,
120
+ id: string,
121
+ ): MonitorStepsReference | undefined => {
122
+ return references.find((reference: MonitorStepsReference) => {
123
+ return reference.id === id;
124
+ });
125
+ };
126
+
127
+ describe("MonitorStepsReferenceExtractor", () => {
128
+ describe("what counts as a reference", () => {
129
+ it("returns the default monitor status", () => {
130
+ const references: Array<MonitorStepsReference> =
131
+ MonitorStepsReferenceExtractor.extract(stepsWithCriteria([]));
132
+
133
+ expect(
134
+ idsFor(references, MonitorStepsReferenceModel.MonitorStatus),
135
+ ).toEqual([DEFAULT_STATUS_ID]);
136
+ });
137
+
138
+ it("returns the status a criteria switches the monitor to", () => {
139
+ const references: Array<MonitorStepsReference> =
140
+ MonitorStepsReferenceExtractor.extract(
141
+ stepsWithCriteria([
142
+ criteriaInstance({
143
+ monitorStatusId: STATUS_ID,
144
+ changeMonitorStatus: true,
145
+ }),
146
+ ]),
147
+ );
148
+
149
+ expect(
150
+ idsFor(references, MonitorStepsReferenceModel.MonitorStatus),
151
+ ).toContain(STATUS_ID);
152
+ });
153
+
154
+ it("returns every id a criteria's incident template carries", () => {
155
+ const references: Array<MonitorStepsReference> =
156
+ MonitorStepsReferenceExtractor.extract(
157
+ stepsWithCriteria([
158
+ criteriaInstance({
159
+ createIncidents: true,
160
+ incidents: [
161
+ {
162
+ id: INCIDENT_TEMPLATE_ID,
163
+ title: "Down",
164
+ description: "",
165
+ incidentSeverityId: objectIdJSON(INCIDENT_SEVERITY_ID),
166
+ onCallPolicyIds: [objectIdJSON(ON_CALL_POLICY_ID)],
167
+ labelIds: [objectIdJSON(LABEL_ID)],
168
+ ownerTeamIds: [objectIdJSON(TEAM_ID)],
169
+ ownerUserIds: [objectIdJSON(USER_ID)],
170
+ incidentMemberRoles: [
171
+ {
172
+ roleId: objectIdJSON(ROLE_ID),
173
+ userId: objectIdJSON(USER_ID),
174
+ },
175
+ ],
176
+ },
177
+ ],
178
+ }),
179
+ ]),
180
+ );
181
+
182
+ expect(
183
+ idsFor(references, MonitorStepsReferenceModel.IncidentSeverity),
184
+ ).toEqual([INCIDENT_SEVERITY_ID]);
185
+ expect(
186
+ idsFor(references, MonitorStepsReferenceModel.OnCallDutyPolicy),
187
+ ).toEqual([ON_CALL_POLICY_ID]);
188
+ expect(idsFor(references, MonitorStepsReferenceModel.Label)).toEqual([
189
+ LABEL_ID,
190
+ ]);
191
+ expect(idsFor(references, MonitorStepsReferenceModel.Team)).toEqual([
192
+ TEAM_ID,
193
+ ]);
194
+ expect(
195
+ idsFor(references, MonitorStepsReferenceModel.IncidentRole),
196
+ ).toEqual([ROLE_ID]);
197
+ // Once as an owner and once as the member the role is assigned to.
198
+ expect(idsFor(references, MonitorStepsReferenceModel.User)).toEqual([
199
+ USER_ID,
200
+ USER_ID,
201
+ ]);
202
+ });
203
+
204
+ it("returns every id a criteria's alert template carries", () => {
205
+ const references: Array<MonitorStepsReference> =
206
+ MonitorStepsReferenceExtractor.extract(
207
+ stepsWithCriteria([
208
+ criteriaInstance({
209
+ createAlerts: true,
210
+ alerts: [
211
+ {
212
+ id: ALERT_TEMPLATE_ID,
213
+ title: "Down",
214
+ description: "",
215
+ alertSeverityId: objectIdJSON(ALERT_SEVERITY_ID),
216
+ onCallPolicyIds: [objectIdJSON(ON_CALL_POLICY_ID)],
217
+ labelIds: [objectIdJSON(LABEL_ID)],
218
+ ownerTeamIds: [objectIdJSON(TEAM_ID)],
219
+ ownerUserIds: [objectIdJSON(USER_ID)],
220
+ },
221
+ ],
222
+ }),
223
+ ]),
224
+ );
225
+
226
+ expect(
227
+ idsFor(references, MonitorStepsReferenceModel.AlertSeverity),
228
+ ).toEqual([ALERT_SEVERITY_ID]);
229
+ expect(
230
+ idsFor(references, MonitorStepsReferenceModel.OnCallDutyPolicy),
231
+ ).toEqual([ON_CALL_POLICY_ID]);
232
+ expect(idsFor(references, MonitorStepsReferenceModel.Label)).toEqual([
233
+ LABEL_ID,
234
+ ]);
235
+ expect(idsFor(references, MonitorStepsReferenceModel.Team)).toEqual([
236
+ TEAM_ID,
237
+ ]);
238
+ expect(idsFor(references, MonitorStepsReferenceModel.User)).toEqual([
239
+ USER_ID,
240
+ ]);
241
+ });
242
+
243
+ it("returns the telemetry services a step is scoped to, from every sub-config that carries them", () => {
244
+ for (const field of [
245
+ "logMonitor",
246
+ "traceMonitor",
247
+ "exceptionMonitor",
248
+ "profileMonitor",
249
+ "metricMonitor",
250
+ ]) {
251
+ const references: Array<MonitorStepsReference> =
252
+ MonitorStepsReferenceExtractor.extract(
253
+ stepsWithCriteria([], {
254
+ [field]: {
255
+ telemetryServiceIds: [objectIdJSON(TELEMETRY_SERVICE_ID)],
256
+ },
257
+ }),
258
+ );
259
+
260
+ expect(
261
+ idsFor(references, MonitorStepsReferenceModel.TelemetryService),
262
+ ).toEqual([TELEMETRY_SERVICE_ID]);
263
+ }
264
+ });
265
+
266
+ it("returns the device a network device step walks", () => {
267
+ const references: Array<MonitorStepsReference> =
268
+ MonitorStepsReferenceExtractor.extract(
269
+ stepsWithCriteria([], {
270
+ networkDeviceMonitor: { networkDeviceId: NETWORK_DEVICE_ID },
271
+ }),
272
+ );
273
+
274
+ expect(
275
+ idsFor(references, MonitorStepsReferenceModel.NetworkDevice),
276
+ ).toEqual([NETWORK_DEVICE_ID]);
277
+ });
278
+ });
279
+
280
+ describe("what is NOT a reference", () => {
281
+ it("never returns the step id, the criteria id, or an incident/alert template id", () => {
282
+ /*
283
+ * These are all `ObjectID.generate()` values minted client-side for local
284
+ * identity — Terraform never sends them, so they are minted again on
285
+ * every write. They match no row anywhere, and returning them is exactly
286
+ * what stopped the old regex-based guard from checking existence.
287
+ */
288
+ const references: Array<MonitorStepsReference> =
289
+ MonitorStepsReferenceExtractor.extract(
290
+ stepsWithCriteria([
291
+ criteriaInstance({
292
+ createIncidents: true,
293
+ createAlerts: true,
294
+ incidents: [
295
+ { id: INCIDENT_TEMPLATE_ID, title: "t", description: "" },
296
+ ],
297
+ alerts: [{ id: ALERT_TEMPLATE_ID, title: "t", description: "" }],
298
+ }),
299
+ ]),
300
+ );
301
+
302
+ const returned: Array<string> = references.map(
303
+ (reference: MonitorStepsReference) => {
304
+ return reference.id;
305
+ },
306
+ );
307
+
308
+ expect(returned).not.toContain(STEP_ID);
309
+ expect(returned).not.toContain(CRITERIA_ID);
310
+ expect(returned).not.toContain(INCIDENT_TEMPLATE_ID);
311
+ expect(returned).not.toContain(ALERT_TEMPLATE_ID);
312
+ });
313
+
314
+ it("skips a blank id rather than reporting it as a missing reference", () => {
315
+ /*
316
+ * A stored `{"_type":"ObjectID","value":""}` rehydrates to
317
+ * `new ObjectID("")`, which is truthy. Reporting it as a missing
318
+ * *reference* would be misleading — it is an unset field, and the
319
+ * required-field checks own that case.
320
+ */
321
+ const references: Array<MonitorStepsReference> =
322
+ MonitorStepsReferenceExtractor.extract(
323
+ stepsWithCriteria([
324
+ criteriaInstance({
325
+ monitorStatusId: "",
326
+ changeMonitorStatus: true,
327
+ createIncidents: true,
328
+ incidents: [
329
+ {
330
+ id: INCIDENT_TEMPLATE_ID,
331
+ title: "t",
332
+ description: "",
333
+ incidentSeverityId: objectIdJSON(""),
334
+ },
335
+ ],
336
+ }),
337
+ ]),
338
+ );
339
+
340
+ expect(
341
+ idsFor(references, MonitorStepsReferenceModel.IncidentSeverity),
342
+ ).toEqual([]);
343
+ expect(
344
+ idsFor(references, MonitorStepsReferenceModel.MonitorStatus),
345
+ ).toEqual([DEFAULT_STATUS_ID]);
346
+ });
347
+ });
348
+
349
+ describe("isOperative — which references the monitor actually reads", () => {
350
+ it("marks the default monitor status operative, because the monitor is stamped with it", () => {
351
+ const references: Array<MonitorStepsReference> =
352
+ MonitorStepsReferenceExtractor.extract(stepsWithCriteria([]));
353
+
354
+ expect(findById(references, DEFAULT_STATUS_ID)?.isOperative).toBe(true);
355
+ });
356
+
357
+ it("marks a criteria status operative only when the criteria changes the status", () => {
358
+ const on: Array<MonitorStepsReference> =
359
+ MonitorStepsReferenceExtractor.extract(
360
+ stepsWithCriteria([
361
+ criteriaInstance({
362
+ monitorStatusId: STATUS_ID,
363
+ changeMonitorStatus: true,
364
+ }),
365
+ ]),
366
+ );
367
+
368
+ const off: Array<MonitorStepsReference> =
369
+ MonitorStepsReferenceExtractor.extract(
370
+ stepsWithCriteria([
371
+ criteriaInstance({
372
+ monitorStatusId: STATUS_ID,
373
+ changeMonitorStatus: false,
374
+ }),
375
+ ]),
376
+ );
377
+
378
+ expect(findById(on, STATUS_ID)?.isOperative).toBe(true);
379
+ expect(findById(off, STATUS_ID)?.isOperative).toBe(false);
380
+ });
381
+
382
+ it("marks incident template ids operative only when the criteria creates incidents", () => {
383
+ const incidents: Array<JSONValue> = [
384
+ {
385
+ id: INCIDENT_TEMPLATE_ID,
386
+ title: "t",
387
+ description: "",
388
+ incidentSeverityId: objectIdJSON(INCIDENT_SEVERITY_ID),
389
+ onCallPolicyIds: [objectIdJSON(ON_CALL_POLICY_ID)],
390
+ },
391
+ ];
392
+
393
+ const on: Array<MonitorStepsReference> =
394
+ MonitorStepsReferenceExtractor.extract(
395
+ stepsWithCriteria([
396
+ criteriaInstance({ createIncidents: true, incidents: incidents }),
397
+ ]),
398
+ );
399
+
400
+ const off: Array<MonitorStepsReference> =
401
+ MonitorStepsReferenceExtractor.extract(
402
+ stepsWithCriteria([
403
+ criteriaInstance({ createIncidents: false, incidents: incidents }),
404
+ ]),
405
+ );
406
+
407
+ expect(findById(on, INCIDENT_SEVERITY_ID)?.isOperative).toBe(true);
408
+ expect(findById(on, ON_CALL_POLICY_ID)?.isOperative).toBe(true);
409
+ expect(findById(off, INCIDENT_SEVERITY_ID)?.isOperative).toBe(false);
410
+ expect(findById(off, ON_CALL_POLICY_ID)?.isOperative).toBe(false);
411
+ });
412
+
413
+ it("marks alert template ids operative only when the criteria creates alerts", () => {
414
+ const alerts: Array<JSONValue> = [
415
+ {
416
+ id: ALERT_TEMPLATE_ID,
417
+ title: "t",
418
+ description: "",
419
+ alertSeverityId: objectIdJSON(ALERT_SEVERITY_ID),
420
+ },
421
+ ];
422
+
423
+ const on: Array<MonitorStepsReference> =
424
+ MonitorStepsReferenceExtractor.extract(
425
+ stepsWithCriteria([
426
+ criteriaInstance({ createAlerts: true, alerts: alerts }),
427
+ ]),
428
+ );
429
+
430
+ const off: Array<MonitorStepsReference> =
431
+ MonitorStepsReferenceExtractor.extract(
432
+ stepsWithCriteria([
433
+ criteriaInstance({ createAlerts: false, alerts: alerts }),
434
+ ]),
435
+ );
436
+
437
+ expect(findById(on, ALERT_SEVERITY_ID)?.isOperative).toBe(true);
438
+ expect(findById(off, ALERT_SEVERITY_ID)?.isOperative).toBe(false);
439
+ });
440
+
441
+ it("never marks a telemetry service or network device operative", () => {
442
+ /*
443
+ * Neither can produce the foreign key violation this guard exists for,
444
+ * both already degrade on their own when the target is gone, and
445
+ * deleting a telemetry service is ordinary enough that requiring it would
446
+ * refuse every later edit of a monitor that once watched it.
447
+ */
448
+ const references: Array<MonitorStepsReference> =
449
+ MonitorStepsReferenceExtractor.extract(
450
+ stepsWithCriteria([], {
451
+ logMonitor: {
452
+ telemetryServiceIds: [objectIdJSON(TELEMETRY_SERVICE_ID)],
453
+ },
454
+ networkDeviceMonitor: { networkDeviceId: NETWORK_DEVICE_ID },
455
+ }),
456
+ );
457
+
458
+ expect(findById(references, TELEMETRY_SERVICE_ID)?.isOperative).toBe(
459
+ false,
460
+ );
461
+ expect(findById(references, NETWORK_DEVICE_ID)?.isOperative).toBe(false);
462
+ });
463
+ });
464
+
465
+ describe("the shapes monitorSteps actually arrives in", () => {
466
+ it("walks a live MonitorSteps object, not just its serialized form", () => {
467
+ const monitorSteps: MonitorSteps = MonitorSteps.fromJSON(
468
+ stepsWithCriteria([
469
+ criteriaInstance({
470
+ monitorStatusId: STATUS_ID,
471
+ changeMonitorStatus: true,
472
+ }),
473
+ ]),
474
+ );
475
+
476
+ const references: Array<MonitorStepsReference> =
477
+ MonitorStepsReferenceExtractor.extract(monitorSteps);
478
+
479
+ expect(
480
+ idsFor(references, MonitorStepsReferenceModel.MonitorStatus).sort(),
481
+ ).toEqual([DEFAULT_STATUS_ID, STATUS_ID].sort());
482
+ });
483
+
484
+ it("accepts a payload with no _type/value envelope", () => {
485
+ /*
486
+ * A hand-written REST body does not have to carry the envelopes the
487
+ * dashboard emits, and it must be walked just as thoroughly.
488
+ */
489
+ const references: Array<MonitorStepsReference> =
490
+ MonitorStepsReferenceExtractor.extract({
491
+ defaultMonitorStatusId: DEFAULT_STATUS_ID,
492
+ monitorStepsInstanceArray: [
493
+ {
494
+ id: STEP_ID,
495
+ monitorCriteria: {
496
+ monitorCriteriaInstanceArray: [
497
+ {
498
+ id: CRITERIA_ID,
499
+ monitorStatusId: STATUS_ID,
500
+ changeMonitorStatus: true,
501
+ incidents: [],
502
+ alerts: [],
503
+ },
504
+ ],
505
+ },
506
+ },
507
+ ],
508
+ });
509
+
510
+ expect(
511
+ idsFor(references, MonitorStepsReferenceModel.MonitorStatus).sort(),
512
+ ).toEqual([DEFAULT_STATUS_ID, STATUS_ID].sort());
513
+ });
514
+
515
+ it("reads an id whether it is a bare uuid or an ObjectID envelope", () => {
516
+ const bare: Array<MonitorStepsReference> =
517
+ MonitorStepsReferenceExtractor.extract(
518
+ stepsWithCriteria([
519
+ criteriaInstance({
520
+ createIncidents: true,
521
+ incidents: [
522
+ {
523
+ id: INCIDENT_TEMPLATE_ID,
524
+ title: "t",
525
+ description: "",
526
+ incidentSeverityId: INCIDENT_SEVERITY_ID,
527
+ },
528
+ ],
529
+ }),
530
+ ]),
531
+ );
532
+
533
+ const wrapped: Array<MonitorStepsReference> =
534
+ MonitorStepsReferenceExtractor.extract(
535
+ stepsWithCriteria([
536
+ criteriaInstance({
537
+ createIncidents: true,
538
+ incidents: [
539
+ {
540
+ id: INCIDENT_TEMPLATE_ID,
541
+ title: "t",
542
+ description: "",
543
+ incidentSeverityId: objectIdJSON(INCIDENT_SEVERITY_ID),
544
+ },
545
+ ],
546
+ }),
547
+ ]),
548
+ );
549
+
550
+ expect(idsFor(bare, MonitorStepsReferenceModel.IncidentSeverity)).toEqual(
551
+ [INCIDENT_SEVERITY_ID],
552
+ );
553
+ expect(
554
+ idsFor(wrapped, MonitorStepsReferenceModel.IncidentSeverity),
555
+ ).toEqual([INCIDENT_SEVERITY_ID]);
556
+ });
557
+
558
+ it("walks every step and every criteria, not just the first", () => {
559
+ const references: Array<MonitorStepsReference> =
560
+ MonitorStepsReferenceExtractor.extract({
561
+ _type: ObjectType.MonitorSteps,
562
+ value: {
563
+ defaultMonitorStatusId: DEFAULT_STATUS_ID,
564
+ monitorStepsInstanceArray: [
565
+ {
566
+ _type: ObjectType.MonitorStep,
567
+ value: {
568
+ id: STEP_ID,
569
+ monitorCriteria: {
570
+ _type: ObjectType.MonitorCriteria,
571
+ value: {
572
+ monitorCriteriaInstanceArray: [
573
+ criteriaInstance({
574
+ monitorStatusId: STATUS_ID,
575
+ changeMonitorStatus: true,
576
+ }),
577
+ ],
578
+ },
579
+ },
580
+ },
581
+ },
582
+ {
583
+ _type: ObjectType.MonitorStep,
584
+ value: {
585
+ id: STEP_ID,
586
+ monitorCriteria: {
587
+ _type: ObjectType.MonitorCriteria,
588
+ value: {
589
+ monitorCriteriaInstanceArray: [
590
+ criteriaInstance({
591
+ createAlerts: true,
592
+ alerts: [
593
+ {
594
+ id: ALERT_TEMPLATE_ID,
595
+ title: "t",
596
+ description: "",
597
+ alertSeverityId: objectIdJSON(ALERT_SEVERITY_ID),
598
+ },
599
+ ],
600
+ }),
601
+ ],
602
+ },
603
+ },
604
+ },
605
+ },
606
+ ],
607
+ },
608
+ });
609
+
610
+ expect(
611
+ idsFor(references, MonitorStepsReferenceModel.MonitorStatus),
612
+ ).toContain(STATUS_ID);
613
+ expect(
614
+ idsFor(references, MonitorStepsReferenceModel.AlertSeverity),
615
+ ).toEqual([ALERT_SEVERITY_ID]);
616
+ });
617
+
618
+ it("returns nothing rather than throwing on absent or malformed input", () => {
619
+ /*
620
+ * monitorSteps is a free-form JSON column and older rows can be
621
+ * malformed — MonitorSteps.fromDatabase is deliberately lenient about
622
+ * that for the same reason. A guard that threw here would make such a row
623
+ * impossible to save OR delete.
624
+ */
625
+ expect(MonitorStepsReferenceExtractor.extract(undefined)).toEqual([]);
626
+ expect(MonitorStepsReferenceExtractor.extract(null)).toEqual([]);
627
+ expect(MonitorStepsReferenceExtractor.extract({})).toEqual([]);
628
+ expect(
629
+ MonitorStepsReferenceExtractor.extract({
630
+ _type: ObjectType.MonitorSteps,
631
+ value: { monitorStepsInstanceArray: "not an array" },
632
+ }),
633
+ ).toEqual([]);
634
+ expect(
635
+ MonitorStepsReferenceExtractor.extract({
636
+ _type: ObjectType.MonitorSteps,
637
+ value: {
638
+ monitorStepsInstanceArray: [null, 7, "nope", { value: null }],
639
+ },
640
+ }),
641
+ ).toEqual([]);
642
+ expect(
643
+ MonitorStepsReferenceExtractor.extract(new MonitorSteps()),
644
+ ).toEqual([]);
645
+ });
646
+ });
647
+
648
+ describe("path — where the message points the user", () => {
649
+ it("names the criteria and the field", () => {
650
+ const references: Array<MonitorStepsReference> =
651
+ MonitorStepsReferenceExtractor.extract(
652
+ stepsWithCriteria([
653
+ criteriaInstance({
654
+ monitorStatusId: STATUS_ID,
655
+ changeMonitorStatus: true,
656
+ createIncidents: true,
657
+ incidents: [
658
+ {
659
+ id: INCIDENT_TEMPLATE_ID,
660
+ title: "t",
661
+ description: "",
662
+ incidentSeverityId: objectIdJSON(INCIDENT_SEVERITY_ID),
663
+ onCallPolicyIds: [objectIdJSON(ON_CALL_POLICY_ID)],
664
+ },
665
+ ],
666
+ }),
667
+ ]),
668
+ );
669
+
670
+ expect(findById(references, DEFAULT_STATUS_ID)?.path).toBe(
671
+ "default monitor status",
672
+ );
673
+ expect(findById(references, STATUS_ID)?.path).toBe(
674
+ 'criteria "Monitor is offline" monitor status',
675
+ );
676
+ expect(findById(references, INCIDENT_SEVERITY_ID)?.path).toBe(
677
+ 'criteria "Monitor is offline" incident severity',
678
+ );
679
+ expect(findById(references, ON_CALL_POLICY_ID)?.path).toBe(
680
+ 'criteria "Monitor is offline" incident on-call policy',
681
+ );
682
+ });
683
+
684
+ it("falls back to the criteria's position when it has no name", () => {
685
+ const references: Array<MonitorStepsReference> =
686
+ MonitorStepsReferenceExtractor.extract(
687
+ stepsWithCriteria([
688
+ criteriaInstance({
689
+ name: "",
690
+ monitorStatusId: STATUS_ID,
691
+ changeMonitorStatus: true,
692
+ }),
693
+ ]),
694
+ );
695
+
696
+ expect(findById(references, STATUS_ID)?.path).toBe(
697
+ 'criteria "#1" monitor status',
698
+ );
699
+ });
700
+ });
701
+
702
+ describe("toReferenceId", () => {
703
+ it("reads every shape an id arrives in", () => {
704
+ expect(toReferenceId(STATUS_ID)).toBe(STATUS_ID);
705
+ expect(toReferenceId(new ObjectID(STATUS_ID))).toBe(STATUS_ID);
706
+ expect(toReferenceId(objectIdJSON(STATUS_ID))).toBe(STATUS_ID);
707
+ // The marker-less `{ value }` shape MonitorCriteriaInstance.fromJSON accepts.
708
+ expect(toReferenceId({ value: STATUS_ID })).toBe(STATUS_ID);
709
+ expect(toReferenceId(` ${STATUS_ID} `)).toBe(STATUS_ID);
710
+ });
711
+
712
+ it("treats absent, blank and non-id values as no reference", () => {
713
+ expect(toReferenceId(undefined)).toBeNull();
714
+ expect(toReferenceId(null)).toBeNull();
715
+ expect(toReferenceId("")).toBeNull();
716
+ expect(toReferenceId(" ")).toBeNull();
717
+ expect(toReferenceId(objectIdJSON(""))).toBeNull();
718
+ expect(toReferenceId(new ObjectID(""))).toBeNull();
719
+ expect(toReferenceId(42)).toBeNull();
720
+ expect(toReferenceId([STATUS_ID] as unknown as JSONValue)).toBeNull();
721
+ expect(toReferenceId({ notAValue: STATUS_ID })).toBeNull();
722
+ });
723
+ });
724
+ });