@oneuptime/common 11.7.2 → 11.7.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 (414) hide show
  1. package/Models/AnalyticsModels/KubernetesCostAllocation.ts +103 -0
  2. package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +1 -0
  3. package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
  4. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  5. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  6. package/Models/DatabaseModels/Index.ts +5 -0
  7. package/Models/DatabaseModels/LogDropFilter.ts +89 -0
  8. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +13 -3
  9. package/Models/DatabaseModels/RecommendationDismissal.ts +463 -0
  10. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  11. package/Models/DatabaseModels/StatusPageGroup.ts +95 -0
  12. package/Models/DatabaseModels/TableView.ts +40 -0
  13. package/Models/DatabaseModels/TraceDropFilter.ts +89 -0
  14. package/Models/DatabaseModels/WorkflowVariable.ts +5 -1
  15. package/Server/API/AlertAPI.ts +32 -17
  16. package/Server/API/BaseAPI.ts +31 -2
  17. package/Server/API/BaseAnalyticsAPI.ts +36 -2
  18. package/Server/API/CommonAPI.ts +57 -0
  19. package/Server/API/IncidentAPI.ts +60 -33
  20. package/Server/API/IncidentEpisodeAPI.ts +31 -16
  21. package/Server/API/MonitorAPI.ts +30 -0
  22. package/Server/API/MonitorTemplateAPI.ts +8 -0
  23. package/Server/API/ProbeAPI.ts +196 -15
  24. package/Server/API/ProjectAPI.ts +79 -1
  25. package/Server/API/ScheduledMaintenanceAPI.ts +33 -18
  26. package/Server/API/StatusPageAPI.ts +74 -37
  27. package/Server/API/WorkspaceNotificationRuleAPI.ts +34 -4
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.ts +13 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.ts +527 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.ts +31 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.ts +55 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.ts +53 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  34. package/Server/Services/AlertEpisodeService.ts +47 -0
  35. package/Server/Services/AlertService.ts +125 -0
  36. package/Server/Services/BillingService.ts +98 -0
  37. package/Server/Services/DatabaseService.ts +184 -20
  38. package/Server/Services/IncidentEpisodeService.ts +47 -0
  39. package/Server/Services/IncidentService.ts +123 -0
  40. package/Server/Services/IncidentTemplateService.ts +123 -1
  41. package/Server/Services/Index.ts +2 -0
  42. package/Server/Services/LogDropFilterService.ts +133 -0
  43. package/Server/Services/MonitorProbeService.ts +94 -4
  44. package/Server/Services/MonitorService.ts +48 -43
  45. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +70 -0
  46. package/Server/Services/ProbeService.ts +66 -0
  47. package/Server/Services/ProjectService.ts +131 -7
  48. package/Server/Services/RecommendationDismissalService.ts +52 -0
  49. package/Server/Services/RunbookAgentJobService.ts +68 -7
  50. package/Server/Services/ScheduledMaintenanceService.ts +103 -0
  51. package/Server/Services/ScheduledMaintenanceTemplateService.ts +90 -0
  52. package/Server/Services/StatusPageGroupService.ts +186 -0
  53. package/Server/Services/TraceDropFilterService.ts +133 -0
  54. package/Server/Types/Workflow/Components/API/Delete.ts +12 -0
  55. package/Server/Types/Workflow/Components/API/Get.ts +12 -0
  56. package/Server/Types/Workflow/Components/API/Patch.ts +12 -0
  57. package/Server/Types/Workflow/Components/API/Post.ts +12 -0
  58. package/Server/Types/Workflow/Components/API/Put.ts +13 -0
  59. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +212 -0
  60. package/Server/Utils/DropFilterValidation.ts +127 -0
  61. package/Server/Utils/Errors.ts +5 -0
  62. package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
  63. package/Server/Utils/Monitor/MonitorIncident.ts +31 -2
  64. package/Server/Utils/Telemetry/AppMetrics.ts +31 -0
  65. package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +16 -0
  66. package/Tests/Models/DatabaseModels/MonitorProbeColumnAccessControl.test.ts +196 -0
  67. package/Tests/Models/RecommendationDismissalModel.test.ts +269 -0
  68. package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +320 -0
  69. package/Tests/Server/API/BaseAnalyticsAPIUpdatePayloadValidation.test.ts +293 -0
  70. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +164 -0
  71. package/Tests/Server/API/ProbeAPI.test.ts +422 -53
  72. package/Tests/Server/API/ProjectAPI.test.ts +180 -0
  73. package/Tests/Server/API/ProjectAPIExtendTrialBillingDisabled.test.ts +138 -0
  74. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +458 -0
  75. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +359 -0
  76. package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +427 -0
  77. package/Tests/Server/Services/BillingServiceExtendTrial.test.ts +439 -0
  78. package/Tests/Server/Services/CrossProjectReferenceWriteGuard.test.ts +810 -0
  79. package/Tests/Server/Services/DatabaseServiceAtomicAddToColumns.test.ts +269 -0
  80. package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +277 -0
  81. package/Tests/Server/Services/DatabaseServiceSortColumnSelect.test.ts +201 -0
  82. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +81 -23
  83. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +398 -0
  84. package/Tests/Server/Services/MonitorProbeDeleteHooks.test.ts +280 -0
  85. package/Tests/Server/Services/MonitorProbeServiceProbeTenancy.test.ts +304 -0
  86. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +262 -0
  87. package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +614 -0
  88. package/Tests/Server/Services/RecommendationDismissalService.test.ts +306 -0
  89. package/Tests/Server/Services/RepairCrossProjectIncidentReferencesMigration.test.ts +528 -0
  90. package/Tests/Server/Services/StatusPageGroupNesting.test.ts +395 -0
  91. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +26 -21
  92. package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +227 -0
  93. package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +285 -0
  94. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +463 -0
  95. package/Tests/Server/Utils/DropFilterValidation.test.ts +269 -0
  96. package/Tests/Server/Utils/Telemetry/SpanUtil.test.ts +94 -0
  97. package/Tests/Types/DateUserTimezone.test.ts +52 -0
  98. package/Tests/Types/JSONFunctions.test.ts +103 -1
  99. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +177 -9
  100. package/Tests/Types/Monitor/MonitorStepDnsMonitor.test.ts +105 -0
  101. package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +131 -0
  102. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +60 -0
  103. package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +82 -0
  104. package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +268 -0
  105. package/Tests/Types/Monitor/MonitorStepMetricMonitor.test.ts +386 -0
  106. package/Tests/Types/Monitor/MonitorStepProfileMonitor.test.ts +185 -0
  107. package/Tests/Types/Monitor/MonitorStepSnmpMonitor.test.ts +156 -0
  108. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +371 -0
  109. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +901 -0
  110. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +607 -0
  111. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +754 -0
  112. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +960 -0
  113. package/Tests/Types/RollingTime/RollingTimeUtil.test.ts +186 -0
  114. package/Tests/Types/Runbook/RunbookStepTimeout.test.ts +410 -0
  115. package/Tests/Types/Telemetry/DropFilterSampling.test.ts +241 -0
  116. package/Tests/Types/Workspace/NotificationRuleConditionUtil.test.ts +353 -0
  117. package/Tests/Types/Workspace/NotificationRuleUtil.test.ts +566 -0
  118. package/Tests/UI/Components/CodeEditor.test.tsx +174 -0
  119. package/Tests/UI/Components/ErrorBoundary.test.tsx +555 -24
  120. package/Tests/UI/Components/InfoCard.test.tsx +358 -0
  121. package/Tests/UI/Components/LogTimeRangePicker.test.tsx +138 -0
  122. package/Tests/UI/Components/Modal.test.tsx +43 -5
  123. package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +679 -0
  124. package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +397 -0
  125. package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +999 -0
  126. package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +1678 -0
  127. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1094 -0
  128. package/Tests/UI/Components/Runbook/StepTimeoutInput.test.tsx +386 -0
  129. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +671 -0
  130. package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +404 -0
  131. package/Tests/UI/Utils/DropdownAlignment.test.ts +306 -0
  132. package/Tests/UI/Utils/TableFilterUrlState.test.ts +292 -0
  133. package/Tests/Utils/Monitor/MonitorSummaryProbeUtil.test.ts +263 -0
  134. package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +583 -0
  135. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +1072 -0
  136. package/Tests/Utils/StatusPage/GroupTree.test.ts +583 -0
  137. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +411 -0
  138. package/Tests/Utils/UserPreferences.test.ts +563 -0
  139. package/Types/Date.ts +15 -6
  140. package/Types/JSONFunctions.ts +7 -2
  141. package/Types/Kubernetes/KubernetesCostIngest.ts +37 -1
  142. package/Types/Monitor/KubernetesAlertTemplates.ts +205 -0
  143. package/Types/Monitor/MonitorStep.ts +10 -1
  144. package/Types/Monitor/MonitorStepMetricMonitor.ts +46 -1
  145. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +413 -0
  146. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +168 -0
  147. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +175 -0
  148. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +743 -0
  149. package/Types/Permission.ts +45 -0
  150. package/Types/Recommendation/RecommendationType.ts +20 -0
  151. package/Types/Runbook/RunbookExecutionDeadline.ts +129 -0
  152. package/Types/Runbook/RunbookStepTimeout.ts +202 -0
  153. package/Types/Telemetry/DropFilterSampling.ts +92 -0
  154. package/UI/Components/AI/GenerateFromAIModal.tsx +0 -2
  155. package/UI/Components/Accordion/Accordion.tsx +10 -2
  156. package/UI/Components/BulkUpdate/BulkLabelActions.tsx +0 -1
  157. package/UI/Components/CodeEditor/CodeEditor.tsx +34 -20
  158. package/UI/Components/Date/RangeStartAndEndDateView.tsx +0 -1
  159. package/UI/Components/EditionLabel/EditionLabel.tsx +1 -27
  160. package/UI/Components/Error/PageError.tsx +0 -4
  161. package/UI/Components/ErrorBoundary.tsx +252 -15
  162. package/UI/Components/InfoCard/InfoCard.tsx +58 -1
  163. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +34 -1
  164. package/UI/Components/MasterPage/MasterPage.tsx +65 -0
  165. package/UI/Components/Modal/Modal.tsx +16 -60
  166. package/UI/Components/ModelFormModal/ModelFormModal.tsx +0 -8
  167. package/UI/Components/ModelTable/BaseModelTable.tsx +503 -71
  168. package/UI/Components/ModelTable/Column.ts +17 -0
  169. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +523 -0
  170. package/UI/Components/ModelTable/ColumnPreference.ts +482 -0
  171. package/UI/Components/ModelTable/CustomFieldColumns.tsx +326 -0
  172. package/UI/Components/ModelTable/TableView.tsx +24 -2
  173. package/UI/Components/ModelTable/useCustomFieldColumns.ts +150 -0
  174. package/UI/Components/Runbook/StepTimeoutInput.tsx +173 -0
  175. package/UI/Components/SideMenu/SideMenu.tsx +24 -4
  176. package/UI/Components/StatusPage/ResourceGroupSection.tsx +231 -0
  177. package/UI/Components/Table/Table.tsx +14 -1
  178. package/UI/Components/Table/TableRow.tsx +180 -175
  179. package/UI/Components/Table/Types/Column.ts +2 -0
  180. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +34 -1
  181. package/UI/Utils/DropdownAlignment.ts +162 -0
  182. package/UI/Utils/TableFilterUrlState.ts +59 -20
  183. package/Utils/API.ts +106 -2
  184. package/Utils/Monitor/MonitorSummaryProbeUtil.ts +130 -0
  185. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +434 -0
  186. package/Utils/StatusPage/GroupNestingLayout.ts +343 -0
  187. package/Utils/StatusPage/GroupTree.ts +307 -0
  188. package/Utils/StatusPage/ResourceUptime.ts +90 -17
  189. package/Utils/UserPreferences.ts +53 -0
  190. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +86 -0
  191. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
  193. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
  195. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
  196. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  197. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  199. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  201. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/LogDropFilter.js +91 -0
  203. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +14 -4
  205. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js +484 -0
  207. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js.map +1 -0
  208. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  209. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/StatusPageGroup.js +94 -0
  211. package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
  212. package/build/dist/Models/DatabaseModels/TableView.js +40 -0
  213. package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
  214. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +91 -0
  215. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  216. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +5 -1
  217. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  218. package/build/dist/Server/API/AlertAPI.js +22 -13
  219. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  220. package/build/dist/Server/API/BaseAPI.js +22 -1
  221. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  222. package/build/dist/Server/API/BaseAnalyticsAPI.js +24 -1
  223. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  224. package/build/dist/Server/API/CommonAPI.js +42 -0
  225. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  226. package/build/dist/Server/API/IncidentAPI.js +43 -26
  227. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  228. package/build/dist/Server/API/IncidentEpisodeAPI.js +21 -12
  229. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  230. package/build/dist/Server/API/MonitorAPI.js +23 -0
  231. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  232. package/build/dist/Server/API/MonitorTemplateAPI.js +4 -0
  233. package/build/dist/Server/API/MonitorTemplateAPI.js.map +1 -1
  234. package/build/dist/Server/API/ProbeAPI.js +131 -15
  235. package/build/dist/Server/API/ProbeAPI.js.map +1 -1
  236. package/build/dist/Server/API/ProjectAPI.js +62 -3
  237. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  238. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +23 -14
  239. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  240. package/build/dist/Server/API/StatusPageAPI.js +61 -33
  241. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  242. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js +26 -2
  243. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js.map +1 -1
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js +12 -0
  245. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js.map +1 -0
  246. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js +397 -0
  247. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js.map +1 -0
  248. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js +16 -0
  249. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js.map +1 -0
  250. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js +30 -0
  251. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js.map +1 -0
  252. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js +34 -0
  253. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js.map +1 -0
  254. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  255. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  256. package/build/dist/Server/Services/AlertEpisodeService.js +39 -0
  257. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  258. package/build/dist/Server/Services/AlertService.js +95 -0
  259. package/build/dist/Server/Services/AlertService.js.map +1 -1
  260. package/build/dist/Server/Services/BillingService.js +71 -0
  261. package/build/dist/Server/Services/BillingService.js.map +1 -1
  262. package/build/dist/Server/Services/DatabaseService.js +140 -17
  263. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  264. package/build/dist/Server/Services/IncidentEpisodeService.js +39 -0
  265. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  266. package/build/dist/Server/Services/IncidentService.js +100 -0
  267. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  268. package/build/dist/Server/Services/IncidentTemplateService.js +97 -0
  269. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  270. package/build/dist/Server/Services/Index.js +2 -0
  271. package/build/dist/Server/Services/Index.js.map +1 -1
  272. package/build/dist/Server/Services/LogDropFilterService.js +93 -0
  273. package/build/dist/Server/Services/LogDropFilterService.js.map +1 -1
  274. package/build/dist/Server/Services/MonitorProbeService.js +73 -5
  275. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  276. package/build/dist/Server/Services/MonitorService.js +34 -39
  277. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  278. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +71 -0
  279. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  280. package/build/dist/Server/Services/ProbeService.js +64 -0
  281. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  282. package/build/dist/Server/Services/ProjectService.js +103 -7
  283. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  284. package/build/dist/Server/Services/RecommendationDismissalService.js +50 -0
  285. package/build/dist/Server/Services/RecommendationDismissalService.js.map +1 -0
  286. package/build/dist/Server/Services/RunbookAgentJobService.js +63 -5
  287. package/build/dist/Server/Services/RunbookAgentJobService.js.map +1 -1
  288. package/build/dist/Server/Services/ScheduledMaintenanceService.js +83 -0
  289. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  290. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +65 -0
  291. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  292. package/build/dist/Server/Services/StatusPageGroupService.js +136 -0
  293. package/build/dist/Server/Services/StatusPageGroupService.js.map +1 -1
  294. package/build/dist/Server/Services/TraceDropFilterService.js +93 -0
  295. package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -1
  296. package/build/dist/Server/Types/Workflow/Components/API/Delete.js +11 -0
  297. package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
  298. package/build/dist/Server/Types/Workflow/Components/API/Get.js +11 -0
  299. package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
  300. package/build/dist/Server/Types/Workflow/Components/API/Patch.js +11 -0
  301. package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
  302. package/build/dist/Server/Types/Workflow/Components/API/Post.js +11 -0
  303. package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
  304. package/build/dist/Server/Types/Workflow/Components/API/Put.js +12 -0
  305. package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
  306. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +132 -0
  307. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -0
  308. package/build/dist/Server/Utils/DropFilterValidation.js +80 -0
  309. package/build/dist/Server/Utils/DropFilterValidation.js.map +1 -0
  310. package/build/dist/Server/Utils/Errors.js +3 -0
  311. package/build/dist/Server/Utils/Errors.js.map +1 -1
  312. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +30 -12
  313. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  314. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +38 -18
  315. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  316. package/build/dist/Server/Utils/Telemetry/AppMetrics.js +26 -0
  317. package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
  318. package/build/dist/Types/Date.js +14 -4
  319. package/build/dist/Types/Date.js.map +1 -1
  320. package/build/dist/Types/JSONFunctions.js +8 -3
  321. package/build/dist/Types/JSONFunctions.js.map +1 -1
  322. package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -1
  323. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +192 -0
  324. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  325. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  326. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  327. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +32 -1
  328. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
  329. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +294 -0
  330. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -0
  331. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +110 -0
  332. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -0
  333. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +58 -0
  334. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -0
  335. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +451 -0
  336. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -0
  337. package/build/dist/Types/Permission.js +40 -0
  338. package/build/dist/Types/Permission.js.map +1 -1
  339. package/build/dist/Types/Recommendation/RecommendationType.js +21 -0
  340. package/build/dist/Types/Recommendation/RecommendationType.js.map +1 -0
  341. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js +93 -0
  342. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js.map +1 -0
  343. package/build/dist/Types/Runbook/RunbookStepTimeout.js +142 -0
  344. package/build/dist/Types/Runbook/RunbookStepTimeout.js.map +1 -0
  345. package/build/dist/Types/Telemetry/DropFilterSampling.js +75 -0
  346. package/build/dist/Types/Telemetry/DropFilterSampling.js.map +1 -0
  347. package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -2
  348. package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
  349. package/build/dist/UI/Components/Accordion/Accordion.js +9 -2
  350. package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
  351. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +1 -1
  352. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
  353. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +27 -14
  354. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  355. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +1 -1
  356. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -1
  357. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +2 -20
  358. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  359. package/build/dist/UI/Components/Error/PageError.js +1 -3
  360. package/build/dist/UI/Components/Error/PageError.js.map +1 -1
  361. package/build/dist/UI/Components/ErrorBoundary.js +145 -11
  362. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  363. package/build/dist/UI/Components/InfoCard/InfoCard.js +28 -1
  364. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  365. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +13 -2
  366. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  367. package/build/dist/UI/Components/MasterPage/MasterPage.js +50 -1
  368. package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
  369. package/build/dist/UI/Components/Modal/Modal.js +4 -32
  370. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  371. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  372. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +308 -40
  373. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  374. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +230 -0
  375. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -0
  376. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +258 -0
  377. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -0
  378. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +168 -0
  379. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -0
  380. package/build/dist/UI/Components/ModelTable/TableView.js +13 -2
  381. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  382. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +84 -0
  383. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -0
  384. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js +101 -0
  385. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js.map +1 -0
  386. package/build/dist/UI/Components/SideMenu/SideMenu.js +15 -5
  387. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  388. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +73 -0
  389. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -0
  390. package/build/dist/UI/Components/Table/Table.js +15 -2
  391. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  392. package/build/dist/UI/Components/Table/TableRow.js +11 -6
  393. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  394. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +13 -2
  395. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  396. package/build/dist/UI/Utils/DropdownAlignment.js +98 -0
  397. package/build/dist/UI/Utils/DropdownAlignment.js.map +1 -0
  398. package/build/dist/UI/Utils/TableFilterUrlState.js +48 -15
  399. package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
  400. package/build/dist/Utils/API.js +39 -2
  401. package/build/dist/Utils/API.js.map +1 -1
  402. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js +97 -0
  403. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js.map +1 -0
  404. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +330 -0
  405. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -0
  406. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +280 -0
  407. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -0
  408. package/build/dist/Utils/StatusPage/GroupTree.js +214 -0
  409. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -0
  410. package/build/dist/Utils/StatusPage/ResourceUptime.js +60 -16
  411. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  412. package/build/dist/Utils/UserPreferences.js +33 -0
  413. package/build/dist/Utils/UserPreferences.js.map +1 -1
  414. package/package.json +1 -1
@@ -32,6 +32,9 @@ import {
32
32
  import URL from "../../Types/API/URL";
33
33
  import DatabaseConfig from "../DatabaseConfig";
34
34
  import AlertSeverityService from "./AlertSeverityService";
35
+ import ProjectScopedReferenceValidator, {
36
+ resolveReferenceId,
37
+ } from "../Utils/Database/ProjectScopedReferenceValidator";
35
38
  import AlertEpisodeMemberService from "./AlertEpisodeMemberService";
36
39
  import AlertEpisodeOwnerUserService from "./AlertEpisodeOwnerUserService";
37
40
  import AlertEpisodeOwnerTeamService from "./AlertEpisodeOwnerTeamService";
@@ -94,6 +97,36 @@ export class Service extends DatabaseService<Model> {
94
97
  updateBy.query,
95
98
  updateBy.props,
96
99
  );
100
+
101
+ /*
102
+ * An episode carries the same project-scoped state and severity an alert
103
+ * does, on FKs that are equally ON DELETE NO ACTION, so an id from another
104
+ * project here leaves that project undeletable in exactly the same way.
105
+ * onBeforeCreate overwrites currentAlertStateId with this project's
106
+ * created state, which leaves the severity as the only create-reachable
107
+ * column — but an update can write either.
108
+ */
109
+ await ProjectScopedReferenceValidator.validateReferencesBelongToProject({
110
+ projectId: updateBy.props.tenantId,
111
+ subject: "alert episode",
112
+ references: [
113
+ {
114
+ modelName: "Alert State",
115
+ id:
116
+ resolveReferenceId(updateBy.data.currentAlertStateId) ||
117
+ resolveReferenceId(updateBy.data.currentAlertState),
118
+ service: AlertStateService,
119
+ },
120
+ {
121
+ modelName: "Alert Severity",
122
+ id:
123
+ resolveReferenceId(updateBy.data.alertSeverityId) ||
124
+ resolveReferenceId(updateBy.data.alertSeverity),
125
+ service: AlertSeverityService,
126
+ },
127
+ ],
128
+ });
129
+
97
130
  return { updateBy, carryForward: null };
98
131
  }
99
132
 
@@ -141,6 +174,20 @@ export class Service extends DatabaseService<Model> {
141
174
 
142
175
  createBy.data.currentAlertStateId = alertState.id;
143
176
 
177
+ await ProjectScopedReferenceValidator.validateReferencesBelongToProject({
178
+ projectId: projectId,
179
+ subject: "alert episode",
180
+ references: [
181
+ {
182
+ modelName: "Alert Severity",
183
+ id:
184
+ resolveReferenceId(createBy.data.alertSeverityId) ||
185
+ resolveReferenceId(createBy.data.alertSeverity),
186
+ service: AlertSeverityService,
187
+ },
188
+ ],
189
+ });
190
+
144
191
  // Auto-generate episode number
145
192
  const episodeCounterResult: {
146
193
  counter: number;
@@ -29,6 +29,10 @@ import Model from "../../Models/DatabaseModels/Alert";
29
29
  import AlertOwnerTeam from "../../Models/DatabaseModels/AlertOwnerTeam";
30
30
  import AlertOwnerUser from "../../Models/DatabaseModels/AlertOwnerUser";
31
31
  import AlertState from "../../Models/DatabaseModels/AlertState";
32
+ import MonitorStatusService from "./MonitorStatusService";
33
+ import ProjectScopedReferenceValidator, {
34
+ resolveReferenceId,
35
+ } from "../Utils/Database/ProjectScopedReferenceValidator";
32
36
  import AlertStateTimeline from "../../Models/DatabaseModels/AlertStateTimeline";
33
37
  import User from "../../Models/DatabaseModels/User";
34
38
  import { IsBillingEnabled } from "../EnvironmentConfig";
@@ -258,9 +262,98 @@ export class Service extends DatabaseService<Model> {
258
262
  updateBy.query,
259
263
  updateBy.props,
260
264
  );
265
+
266
+ await this.validateProjectScopedReferences(updateBy);
267
+
261
268
  return { updateBy, carryForward: null };
262
269
  }
263
270
 
271
+ /*
272
+ * An update can repoint an alert at another project's state, severity or
273
+ * monitor status just as easily as a create can, and the result is the same:
274
+ * the referenced project can no longer be deleted. Only the columns actually
275
+ * being written are checked, so ordinary updates cost no extra queries.
276
+ */
277
+ private async validateProjectScopedReferences(
278
+ updateBy: UpdateBy<Model>,
279
+ ): Promise<void> {
280
+ const alertStateId: ObjectID | string | undefined =
281
+ resolveReferenceId(updateBy.data.currentAlertStateId) ||
282
+ resolveReferenceId(updateBy.data.currentAlertState);
283
+
284
+ const alertSeverityId: ObjectID | string | undefined =
285
+ resolveReferenceId(updateBy.data.alertSeverityId) ||
286
+ resolveReferenceId(updateBy.data.alertSeverity);
287
+
288
+ const monitorStatusId: ObjectID | string | undefined =
289
+ resolveReferenceId(
290
+ updateBy.data.monitorStatusWhenThisAlertWasCreatedId,
291
+ ) ||
292
+ resolveReferenceId(updateBy.data.monitorStatusWhenThisAlertWasCreated);
293
+
294
+ if (!alertStateId && !alertSeverityId && !monitorStatusId) {
295
+ return;
296
+ }
297
+
298
+ /*
299
+ * Root/API updates do not always carry a tenantId, so fall back to the
300
+ * project of each alert the query actually matches.
301
+ */
302
+ const projectIds: Array<ObjectID> = updateBy.props.tenantId
303
+ ? [updateBy.props.tenantId]
304
+ : await this.getProjectIdsForUpdateQuery(updateBy);
305
+
306
+ for (const projectId of projectIds) {
307
+ await ProjectScopedReferenceValidator.validateReferencesBelongToProject({
308
+ projectId: projectId,
309
+ subject: "alert",
310
+ references: [
311
+ {
312
+ modelName: "Alert State",
313
+ id: alertStateId,
314
+ service: AlertStateService,
315
+ },
316
+ {
317
+ modelName: "Alert Severity",
318
+ id: alertSeverityId,
319
+ service: AlertSeverityService,
320
+ },
321
+ {
322
+ modelName: "Monitor Status",
323
+ id: monitorStatusId,
324
+ service: MonitorStatusService,
325
+ },
326
+ ],
327
+ });
328
+ }
329
+ }
330
+
331
+ private async getProjectIdsForUpdateQuery(
332
+ updateBy: UpdateBy<Model>,
333
+ ): Promise<Array<ObjectID>> {
334
+ const alerts: Array<Model> = await this.findBy({
335
+ query: updateBy.query,
336
+ select: {
337
+ projectId: true,
338
+ },
339
+ limit: LIMIT_MAX,
340
+ skip: 0,
341
+ props: {
342
+ isRoot: true,
343
+ },
344
+ });
345
+
346
+ const projectIds: Dictionary<ObjectID> = {};
347
+
348
+ for (const alert of alerts) {
349
+ if (alert.projectId) {
350
+ projectIds[alert.projectId.toString()] = alert.projectId;
351
+ }
352
+ }
353
+
354
+ return Object.values(projectIds);
355
+ }
356
+
264
357
  @CaptureSpan()
265
358
  protected override async onBeforeCreate(
266
359
  createBy: CreateBy<Model>,
@@ -293,6 +386,38 @@ export class Service extends DatabaseService<Model> {
293
386
 
294
387
  createBy.data.currentAlertStateId = alertState.id;
295
388
 
389
+ /*
390
+ * The severity and the monitor status stamped on the alert come from the
391
+ * monitor criteria or the API caller, neither of which checked that the
392
+ * record belongs to this project. Persisting another project's id leaves
393
+ * that project undeletable. Runs before the counter increment so a
394
+ * rejected create does not burn an alert number.
395
+ */
396
+ await ProjectScopedReferenceValidator.validateReferencesBelongToProject({
397
+ projectId: projectId,
398
+ subject: "alert",
399
+ references: [
400
+ {
401
+ modelName: "Alert Severity",
402
+ id:
403
+ resolveReferenceId(createBy.data.alertSeverityId) ||
404
+ resolveReferenceId(createBy.data.alertSeverity),
405
+ service: AlertSeverityService,
406
+ },
407
+ {
408
+ modelName: "Monitor Status",
409
+ id:
410
+ resolveReferenceId(
411
+ createBy.data.monitorStatusWhenThisAlertWasCreatedId,
412
+ ) ||
413
+ resolveReferenceId(
414
+ createBy.data.monitorStatusWhenThisAlertWasCreated,
415
+ ),
416
+ service: MonitorStatusService,
417
+ },
418
+ ],
419
+ });
420
+
296
421
  const alertCounterResult: {
297
422
  counter: number;
298
423
  prefix: string | undefined;
@@ -37,6 +37,13 @@ export interface PaymentMethod {
37
37
  isDefault: boolean;
38
38
  }
39
39
 
40
+ /*
41
+ * Stripe rejects a trial_end more than two years past the billing cycle
42
+ * anchor. Enforce the same ceiling here so an admin gets a readable error
43
+ * instead of a raw payment-provider failure.
44
+ */
45
+ export const MAX_TRIAL_LENGTH_IN_DAYS: number = 730;
46
+
40
47
  export interface Invoice {
41
48
  id: string;
42
49
  amount: number;
@@ -870,6 +877,97 @@ export class BillingService extends BaseService {
870
877
  }
871
878
  }
872
879
 
880
+ /*
881
+ * Moves the trial end of a project's subscriptions to a new date.
882
+ *
883
+ * Both the flat-fee subscription and the metered subscription have to move
884
+ * together: they were created with the same trial_end (see subscribeToPlan),
885
+ * and leaving the metered one behind would start billing usage while the
886
+ * customer still believes they are on trial.
887
+ */
888
+ @CaptureSpan()
889
+ public async extendTrial(data: {
890
+ subscriptionId: string;
891
+ meteredSubscriptionId?: string | undefined;
892
+ trialEndsAt: Date;
893
+ }): Promise<void> {
894
+ if (!this.isBillingEnabled()) {
895
+ throw new BadDataException(Errors.BillingService.BILLING_NOT_ENABLED);
896
+ }
897
+
898
+ if (!OneUptimeDate.isInTheFuture(data.trialEndsAt)) {
899
+ throw new BadDataException(Errors.BillingService.TRIAL_END_DATE_IN_PAST);
900
+ }
901
+
902
+ if (
903
+ OneUptimeDate.isAfter(
904
+ data.trialEndsAt,
905
+ OneUptimeDate.getSomeDaysAfter(MAX_TRIAL_LENGTH_IN_DAYS),
906
+ )
907
+ ) {
908
+ throw new BadDataException(
909
+ Errors.BillingService.TRIAL_END_DATE_TOO_FAR_IN_FUTURE,
910
+ );
911
+ }
912
+
913
+ const subscriptionIds: Array<string> = [data.subscriptionId];
914
+
915
+ if (data.meteredSubscriptionId) {
916
+ subscriptionIds.push(data.meteredSubscriptionId);
917
+ }
918
+
919
+ /*
920
+ * Validate every subscription before touching any of them. Updating the
921
+ * flat-fee subscription and then discovering the metered one is cancelled
922
+ * would leave the project's two subscriptions on different trial dates.
923
+ */
924
+ for (const subscriptionId of subscriptionIds) {
925
+ const subscription: Stripe.Subscription =
926
+ await this.getSubscription(subscriptionId);
927
+
928
+ if (!subscription) {
929
+ throw new BadDataException(
930
+ Errors.BillingService.SUBSCRIPTION_NOT_FOUND,
931
+ );
932
+ }
933
+
934
+ if (
935
+ subscription.status === "canceled" ||
936
+ subscription.status === "incomplete_expired"
937
+ ) {
938
+ throw new BadDataException(
939
+ Errors.BillingService.CANNOT_EXTEND_TRIAL_ON_CANCELLED_SUBSCRIPTION,
940
+ );
941
+ }
942
+ }
943
+
944
+ for (const subscriptionId of subscriptionIds) {
945
+ await this.stripe.subscriptions.update(subscriptionId, {
946
+ trial_end: OneUptimeDate.toUnixTimestamp(data.trialEndsAt),
947
+
948
+ /*
949
+ * Setting trial_end also moves the billing cycle anchor to that date.
950
+ * With the default proration behaviour Stripe raises proration line
951
+ * items for the shifted period, which is exactly the surprise invoice
952
+ * extending a trial is meant to prevent - so prorations are disabled.
953
+ *
954
+ * Caveat: this only silences the flat-fee subscription. Usage-based
955
+ * billing is not subject to proration, so closing the metered
956
+ * subscription's period early still invoices the usage recorded in it.
957
+ * For a project that is still trialing that is nothing (trial usage is
958
+ * not billable), but extending the trial of an already-active project
959
+ * bills its accrued usage immediately - the admin page warns about
960
+ * this before the extension is submitted.
961
+ */
962
+ proration_behavior: "none",
963
+ });
964
+
965
+ logger.debug(
966
+ `Extended trial for subscription ${subscriptionId} to ${data.trialEndsAt.toISOString()}`,
967
+ );
968
+ }
969
+ }
970
+
873
971
  @CaptureSpan()
874
972
  public async getSubscriptionStatus(
875
973
  subscriptionId: string,
@@ -1552,21 +1552,10 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1552
1552
  try {
1553
1553
  this.setTelemetryContextFromProps(findBy.props);
1554
1554
 
1555
- let automaticallyAddedCreatedAtInSelect: boolean = false;
1556
-
1557
1555
  if (!findBy.sort || Object.keys(findBy.sort).length === 0) {
1558
1556
  findBy.sort = {
1559
1557
  createdAt: SortOrder.Descending,
1560
1558
  };
1561
-
1562
- if (!findBy.select) {
1563
- findBy.select = {} as any;
1564
- }
1565
-
1566
- if (!(findBy.select as any)["createdAt"]) {
1567
- (findBy.select as any)["createdAt"] = true;
1568
- automaticallyAddedCreatedAtInSelect = true;
1569
- }
1570
1559
  }
1571
1560
 
1572
1561
  const onFind: OnFind<TBaseModel> = findBy.props.ignoreHooks
@@ -1600,6 +1589,9 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1600
1589
  onBeforeFind.query = result.query;
1601
1590
  onBeforeFind.select = result.select || undefined;
1602
1591
 
1592
+ const sortColumnsAddedToSelect: Array<string> =
1593
+ this.addSortColumnsToSelect(onBeforeFind);
1594
+
1603
1595
  if (!(onBeforeFind.skip instanceof PositiveNumber)) {
1604
1596
  onBeforeFind.skip = new PositiveNumber(onBeforeFind.skip);
1605
1597
  }
@@ -1634,8 +1626,8 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1634
1626
  decryptedItems = this.sanitizeFindByItems(decryptedItems, onBeforeFind);
1635
1627
 
1636
1628
  for (const item of decryptedItems) {
1637
- if (automaticallyAddedCreatedAtInSelect) {
1638
- delete (item as any).createdAt;
1629
+ for (const sortColumn of sortColumnsAddedToSelect) {
1630
+ delete (item as any)[sortColumn];
1639
1631
  }
1640
1632
  }
1641
1633
 
@@ -1652,6 +1644,67 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1652
1644
  }
1653
1645
  }
1654
1646
 
1647
+ /**
1648
+ * Adds every sorted column to the select, and returns the ones it added so
1649
+ * `_findBy` can strip them back off the results.
1650
+ *
1651
+ * A column can be ordered by without being selected in a plain SELECT, but
1652
+ * not once a relation is also selected: the join sends the query down
1653
+ * TypeORM's paginated path, which wraps it and orders the outer SELECT by a
1654
+ * column the inner query only emits when that column was selected. The
1655
+ * request then fails outright with `column distinctAlias.<Alias>_<column>
1656
+ * does not exist`. Callers should not have to know that, so close the gap
1657
+ * here for every sort rather than leaving each call site to remember.
1658
+ *
1659
+ * Deliberately runs *after* the read-permission check. ORDER BY is not
1660
+ * permission-checked, so a column being sorted on is already reaching the
1661
+ * database - adding it to the select must not be able to turn a query that
1662
+ * worked into a permission error. The values never reach the caller.
1663
+ */
1664
+ private addSortColumnsToSelect(findBy: FindBy<TBaseModel>): Array<string> {
1665
+ /*
1666
+ * No select at all means every column is selected, so there is nothing to
1667
+ * fill in.
1668
+ */
1669
+ if (!findBy.select) {
1670
+ return [];
1671
+ }
1672
+
1673
+ const sortColumnsToAdd: Array<string> = Object.keys(
1674
+ findBy.sort || {},
1675
+ ).filter((sortColumn: string) => {
1676
+ if ((findBy.select as any)[sortColumn] !== undefined) {
1677
+ return false;
1678
+ }
1679
+
1680
+ /*
1681
+ * Sorting by a relation orders through the joined table, which has its
1682
+ * own alias - adding the relation to the select here would instead turn
1683
+ * it into a fetched relation.
1684
+ */
1685
+ return (
1686
+ this.model.hasColumn(sortColumn) &&
1687
+ !this.model.isEntityColumn(sortColumn)
1688
+ );
1689
+ });
1690
+
1691
+ if (sortColumnsToAdd.length === 0) {
1692
+ return [];
1693
+ }
1694
+
1695
+ /*
1696
+ * Copied rather than mutated: sanitizeSelect hands back the caller's own
1697
+ * select object, and callers reuse those across queries.
1698
+ */
1699
+ findBy.select = { ...(findBy.select as any) };
1700
+
1701
+ for (const sortColumn of sortColumnsToAdd) {
1702
+ (findBy.select as any)[sortColumn] = true;
1703
+ }
1704
+
1705
+ return sortColumnsToAdd;
1706
+ }
1707
+
1655
1708
  private sanitizeFindByItems(
1656
1709
  items: Array<TBaseModel>,
1657
1710
  findBy: FindBy<TBaseModel>,
@@ -1841,6 +1894,14 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1841
1894
 
1842
1895
  const dataColumns: [string, boolean][] = [];
1843
1896
  const dataKeys: string[] = Object.keys(data);
1897
+
1898
+ /*
1899
+ * An update that carries no columns writes nothing, yet it would still
1900
+ * match rows - so returning the matched count reported a write that
1901
+ * never happened. Treat it like a query that matched nothing instead.
1902
+ */
1903
+ const hasColumnsToUpdate: boolean = dataKeys.length > 0;
1904
+
1844
1905
  for (const key of dataKeys) {
1845
1906
  dataColumns.push([key, true]);
1846
1907
  }
@@ -1879,13 +1940,15 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
1879
1940
  }
1880
1941
  }
1881
1942
 
1882
- const items: Array<TBaseModel> = await this._findBy({
1883
- query: beforeUpdateBy.query,
1884
- skip: updateBy.skip.toNumber(),
1885
- limit: updateBy.limit.toNumber(),
1886
- select: selectColumns,
1887
- props: { isRoot: true, ignoreHooks: true },
1888
- });
1943
+ const items: Array<TBaseModel> = hasColumnsToUpdate
1944
+ ? await this._findBy({
1945
+ query: beforeUpdateBy.query,
1946
+ skip: updateBy.skip.toNumber(),
1947
+ limit: updateBy.limit.toNumber(),
1948
+ select: selectColumns,
1949
+ props: { isRoot: true, ignoreHooks: true },
1950
+ })
1951
+ : [];
1889
1952
 
1890
1953
  for (const item of items) {
1891
1954
  /*
@@ -2176,6 +2239,107 @@ class DatabaseService<TBaseModel extends BaseModel> extends BaseService {
2176
2239
  await repository.manager.query(sql, params);
2177
2240
  }
2178
2241
 
2242
+ /*
2243
+ * Atomically add to numeric columns and set literal columns for one row,
2244
+ * in a SINGLE auto-committed UPDATE, with no hooks and no `version` bump.
2245
+ *
2246
+ * This is the counter-flush primitive. `updateColumnsByIdWithoutHooks`
2247
+ * can't express it (a read-modify-write would lose concurrent writers'
2248
+ * increments, and the value isn't known to the caller), and
2249
+ * `getRepository().increment()` can't either: it goes through
2250
+ * UpdateQueryBuilder, which always appends `version = version + 1`, so an
2251
+ * ingest-driven counter bump would fight the optimistic lock on a row a
2252
+ * human may be editing — and it can't set a second column in the same
2253
+ * statement.
2254
+ *
2255
+ * `COALESCE(col, 0)` so a NULL counter starts from zero rather than
2256
+ * staying NULL forever.
2257
+ *
2258
+ * Column and table identifiers come from entity metadata (never from the
2259
+ * caller) and every value is bound as a parameter, so this is not an
2260
+ * injection surface. Use ONLY for trusted, internal, side-effect-free
2261
+ * column writes.
2262
+ */
2263
+ @CaptureSpan()
2264
+ public async atomicAddToColumnsByIdWithoutHooks(input: {
2265
+ id: ObjectID;
2266
+ add: Partial<Record<keyof TBaseModel, number>>;
2267
+ set?: PartialEntity<TBaseModel> | undefined;
2268
+ }): Promise<void> {
2269
+ if (!input.id) {
2270
+ throw new BadDataException("id is required");
2271
+ }
2272
+
2273
+ const repository: Repository<TBaseModel> = this.getRepository();
2274
+ const metadata: EntityMetadata = repository.metadata;
2275
+ const driver: Driver = repository.manager.connection.driver;
2276
+
2277
+ const setClauses: Array<string> = [];
2278
+ const params: Array<unknown> = [];
2279
+
2280
+ const columnFor: (propertyName: string) => ColumnMetadata = (
2281
+ propertyName: string,
2282
+ ): ColumnMetadata => {
2283
+ const column: ColumnMetadata | undefined =
2284
+ metadata.findColumnWithPropertyName(propertyName);
2285
+ if (!column) {
2286
+ throw new BadDataException(
2287
+ `atomicAddToColumnsByIdWithoutHooks: unknown column "${propertyName}" on "${metadata.tableName}"`,
2288
+ );
2289
+ }
2290
+ return column;
2291
+ };
2292
+
2293
+ for (const [propertyName, delta] of Object.entries(
2294
+ input.add as ObjectLiteral,
2295
+ )) {
2296
+ if (typeof delta !== "number" || !Number.isFinite(delta)) {
2297
+ throw new BadDataException(
2298
+ `atomicAddToColumnsByIdWithoutHooks: "${propertyName}" delta must be a finite number`,
2299
+ );
2300
+ }
2301
+
2302
+ const column: ColumnMetadata = columnFor(propertyName);
2303
+ params.push(delta);
2304
+ const quoted: string = `"${column.databaseName}"`;
2305
+ setClauses.push(`${quoted} = COALESCE(${quoted}, 0) + $${params.length}`);
2306
+ }
2307
+
2308
+ for (const [propertyName, value] of Object.entries(
2309
+ (input.set || {}) as ObjectLiteral,
2310
+ )) {
2311
+ if (typeof value === "function") {
2312
+ throw new BadDataException(
2313
+ `atomicAddToColumnsByIdWithoutHooks: SQL-expression values are not supported (column "${propertyName}"); pass a literal value.`,
2314
+ );
2315
+ }
2316
+
2317
+ const column: ColumnMetadata = columnFor(propertyName);
2318
+ params.push(driver.preparePersistentValue(value, column));
2319
+ setClauses.push(`"${column.databaseName}" = $${params.length}`);
2320
+ }
2321
+
2322
+ if (setClauses.length === 0) {
2323
+ return;
2324
+ }
2325
+
2326
+ if (metadata.updateDateColumn) {
2327
+ setClauses.push(
2328
+ `"${metadata.updateDateColumn.databaseName}" = CURRENT_TIMESTAMP`,
2329
+ );
2330
+ }
2331
+
2332
+ const primaryColumnName: string =
2333
+ metadata.primaryColumns[0]?.databaseName || "_id";
2334
+ params.push(input.id.toString());
2335
+
2336
+ const sql: string = `UPDATE "${metadata.tableName}" SET ${setClauses.join(
2337
+ ", ",
2338
+ )} WHERE "${primaryColumnName}" = $${params.length}`;
2339
+
2340
+ await repository.manager.query(sql, params);
2341
+ }
2342
+
2179
2343
  @CaptureSpan()
2180
2344
  protected async atomicIncrementColumnValueByOne(data: {
2181
2345
  id: ObjectID;
@@ -27,6 +27,9 @@ import { Red500, Yellow500, Purple500 } from "../../Types/BrandColors";
27
27
  import URL from "../../Types/API/URL";
28
28
  import DatabaseConfig from "../DatabaseConfig";
29
29
  import IncidentSeverityService from "./IncidentSeverityService";
30
+ import ProjectScopedReferenceValidator, {
31
+ resolveReferenceId,
32
+ } from "../Utils/Database/ProjectScopedReferenceValidator";
30
33
  import IncidentEpisodeMemberService from "./IncidentEpisodeMemberService";
31
34
  import IncidentEpisodeOwnerUserService from "./IncidentEpisodeOwnerUserService";
32
35
  import IncidentEpisodeOwnerTeamService from "./IncidentEpisodeOwnerTeamService";
@@ -90,6 +93,36 @@ export class Service extends DatabaseService<Model> {
90
93
  updateBy.query,
91
94
  updateBy.props,
92
95
  );
96
+
97
+ /*
98
+ * An episode carries the same project-scoped state and severity an
99
+ * incident does, on FKs that are equally ON DELETE NO ACTION, so an id
100
+ * from another project here leaves that project undeletable in exactly
101
+ * the same way. onBeforeCreate overwrites currentIncidentStateId with
102
+ * this project's created state, which leaves the severity as the only
103
+ * create-reachable column — but an update can write either.
104
+ */
105
+ await ProjectScopedReferenceValidator.validateReferencesBelongToProject({
106
+ projectId: updateBy.props.tenantId,
107
+ subject: "incident episode",
108
+ references: [
109
+ {
110
+ modelName: "Incident State",
111
+ id:
112
+ resolveReferenceId(updateBy.data.currentIncidentStateId) ||
113
+ resolveReferenceId(updateBy.data.currentIncidentState),
114
+ service: IncidentStateService,
115
+ },
116
+ {
117
+ modelName: "Incident Severity",
118
+ id:
119
+ resolveReferenceId(updateBy.data.incidentSeverityId) ||
120
+ resolveReferenceId(updateBy.data.incidentSeverity),
121
+ service: IncidentSeverityService,
122
+ },
123
+ ],
124
+ });
125
+
93
126
  return { updateBy, carryForward: null };
94
127
  }
95
128
 
@@ -140,6 +173,20 @@ export class Service extends DatabaseService<Model> {
140
173
 
141
174
  createBy.data.currentIncidentStateId = incidentState.id;
142
175
 
176
+ await ProjectScopedReferenceValidator.validateReferencesBelongToProject({
177
+ projectId: projectId,
178
+ subject: "incident episode",
179
+ references: [
180
+ {
181
+ modelName: "Incident Severity",
182
+ id:
183
+ resolveReferenceId(createBy.data.incidentSeverityId) ||
184
+ resolveReferenceId(createBy.data.incidentSeverity),
185
+ service: IncidentSeverityService,
186
+ },
187
+ ],
188
+ });
189
+
143
190
  // Auto-generate episode number
144
191
  const episodeCounterResult: {
145
192
  counter: number;