@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
@@ -0,0 +1,614 @@
1
+ import ProjectService from "../../../Server/Services/ProjectService";
2
+ import BillingService from "../../../Server/Services/BillingService";
3
+ import Project from "../../../Models/DatabaseModels/Project";
4
+ import SubscriptionPlan from "../../../Types/Billing/SubscriptionPlan";
5
+ import SubscriptionStatus from "../../../Types/Billing/SubscriptionStatus";
6
+ import OneUptimeDate from "../../../Types/Date";
7
+ import ObjectID from "../../../Types/ObjectID";
8
+ import { describe, expect, it, afterEach } from "@jest/globals";
9
+
10
+ /*
11
+ * ProjectService.extendTrial is the orchestration layer: the payment provider
12
+ * is the source of truth for what the customer is charged, so these tests pin
13
+ * the ordering (Stripe first, project row second) and the fact that a failed
14
+ * push leaves the stored trial date alone. Everything below the service
15
+ * boundary is spied - no database, no Stripe.
16
+ */
17
+
18
+ jest.mock("../../../Server/EnvironmentConfig", () => {
19
+ return {
20
+ ...jest.requireActual("../../../Server/EnvironmentConfig"),
21
+ IsBillingEnabled: true,
22
+
23
+ /*
24
+ * config.env carries a real incoming webhook URL, and reactiveSubscription
25
+ * announces every plan change on it. Blanked so the suite cannot post to
26
+ * Slack.
27
+ */
28
+ NotificationSlackWebhookOnSubscriptionUpdate: "",
29
+ };
30
+ });
31
+
32
+ const PROJECT_ID: ObjectID = new ObjectID(
33
+ "11111111-1111-4111-8111-111111111111",
34
+ );
35
+ const SUBSCRIPTION_ID: string = "sub_main_123";
36
+ const METERED_SUBSCRIPTION_ID: string = "sub_metered_456";
37
+
38
+ function fakeProject(overrides?: Record<string, unknown>): Project {
39
+ return {
40
+ id: PROJECT_ID,
41
+ _id: PROJECT_ID.toString(),
42
+ trialEndsAt: OneUptimeDate.getSomeDaysAfter(2),
43
+ paymentProviderSubscriptionId: SUBSCRIPTION_ID,
44
+ paymentProviderMeteredSubscriptionId: METERED_SUBSCRIPTION_ID,
45
+ ...overrides,
46
+ } as unknown as Project;
47
+ }
48
+
49
+ describe("ProjectService.extendTrial", () => {
50
+ const newTrialEndDate: Date = OneUptimeDate.getSomeDaysAfter(30);
51
+
52
+ afterEach(() => {
53
+ jest.restoreAllMocks();
54
+ });
55
+
56
+ interface ExtendTrialSpies {
57
+ findOneById: jest.SpyInstance;
58
+ extendTrial: jest.SpyInstance;
59
+ getSubscriptionStatus: jest.SpyInstance;
60
+ updateOneById: jest.SpyInstance;
61
+ }
62
+
63
+ function setup(data?: {
64
+ project?: Project | null;
65
+ extendTrialError?: Error;
66
+ }): ExtendTrialSpies {
67
+ const findOneById: jest.SpyInstance = jest
68
+ .spyOn(ProjectService, "findOneById")
69
+ .mockResolvedValue(
70
+ data && data.project !== undefined ? data.project : fakeProject(),
71
+ );
72
+
73
+ const extendTrial: jest.SpyInstance = jest.spyOn(
74
+ BillingService,
75
+ "extendTrial",
76
+ );
77
+
78
+ if (data?.extendTrialError) {
79
+ extendTrial.mockRejectedValue(data.extendTrialError as never);
80
+ } else {
81
+ extendTrial.mockResolvedValue(undefined as never);
82
+ }
83
+
84
+ const getSubscriptionStatus: jest.SpyInstance = jest
85
+ .spyOn(BillingService, "getSubscriptionStatus")
86
+ .mockResolvedValue(SubscriptionStatus.Trialing as never);
87
+
88
+ const updateOneById: jest.SpyInstance = jest
89
+ .spyOn(ProjectService, "updateOneById")
90
+ .mockResolvedValue(undefined as never);
91
+
92
+ return { findOneById, extendTrial, getSubscriptionStatus, updateOneById };
93
+ }
94
+
95
+ describe("guards", () => {
96
+ it("should throw Project not found when the project does not exist", async () => {
97
+ const spies: ExtendTrialSpies = setup({ project: null });
98
+
99
+ await expect(
100
+ ProjectService.extendTrial({
101
+ projectId: PROJECT_ID,
102
+ trialEndsAt: newTrialEndDate,
103
+ }),
104
+ ).rejects.toThrow("Project not found");
105
+
106
+ expect(spies.extendTrial).not.toHaveBeenCalled();
107
+ expect(spies.updateOneById).not.toHaveBeenCalled();
108
+ });
109
+
110
+ it("should throw when the project has no payment provider subscription", async () => {
111
+ const spies: ExtendTrialSpies = setup({
112
+ project: fakeProject({ paymentProviderSubscriptionId: undefined }),
113
+ });
114
+
115
+ await expect(
116
+ ProjectService.extendTrial({
117
+ projectId: PROJECT_ID,
118
+ trialEndsAt: newTrialEndDate,
119
+ }),
120
+ ).rejects.toThrow("Payment Provider subscription not found");
121
+
122
+ expect(spies.extendTrial).not.toHaveBeenCalled();
123
+ });
124
+
125
+ it("should throw when the project has no metered subscription", async () => {
126
+ /*
127
+ * Every billed project gets both subscriptions at creation. A row with
128
+ * only one is broken, and extending half of it would bill usage during
129
+ * the trial - so fail loudly rather than partially apply.
130
+ */
131
+ const spies: ExtendTrialSpies = setup({
132
+ project: fakeProject({
133
+ paymentProviderMeteredSubscriptionId: undefined,
134
+ }),
135
+ });
136
+
137
+ await expect(
138
+ ProjectService.extendTrial({
139
+ projectId: PROJECT_ID,
140
+ trialEndsAt: newTrialEndDate,
141
+ }),
142
+ ).rejects.toThrow("Payment Provider metered subscription not found");
143
+
144
+ expect(spies.extendTrial).not.toHaveBeenCalled();
145
+ expect(spies.updateOneById).not.toHaveBeenCalled();
146
+ });
147
+ });
148
+
149
+ describe("reading the project", () => {
150
+ it("should select the trial date and both subscription ids as root", async () => {
151
+ const spies: ExtendTrialSpies = setup();
152
+
153
+ await ProjectService.extendTrial({
154
+ projectId: PROJECT_ID,
155
+ trialEndsAt: newTrialEndDate,
156
+ });
157
+
158
+ expect(spies.findOneById).toHaveBeenCalledWith({
159
+ id: PROJECT_ID,
160
+ select: {
161
+ _id: true,
162
+ trialEndsAt: true,
163
+ paymentProviderSubscriptionId: true,
164
+ paymentProviderMeteredSubscriptionId: true,
165
+ },
166
+ props: {
167
+ isRoot: true,
168
+ },
169
+ });
170
+ });
171
+ });
172
+
173
+ describe("pushing to the payment provider", () => {
174
+ it("should send both subscription ids and the new date", async () => {
175
+ const spies: ExtendTrialSpies = setup();
176
+
177
+ await ProjectService.extendTrial({
178
+ projectId: PROJECT_ID,
179
+ trialEndsAt: newTrialEndDate,
180
+ });
181
+
182
+ expect(spies.extendTrial).toHaveBeenCalledWith({
183
+ subscriptionId: SUBSCRIPTION_ID,
184
+ meteredSubscriptionId: METERED_SUBSCRIPTION_ID,
185
+ trialEndsAt: newTrialEndDate,
186
+ });
187
+ });
188
+
189
+ it("should not require the customer to have a payment method", async () => {
190
+ /*
191
+ * A trial extension is most useful for a customer who has not entered a
192
+ * card yet, so it deliberately does not gate on one the way changePlan
193
+ * does.
194
+ */
195
+ setup();
196
+
197
+ const hasPaymentMethods: jest.SpyInstance = jest.spyOn(
198
+ BillingService,
199
+ "hasPaymentMethods",
200
+ );
201
+
202
+ await ProjectService.extendTrial({
203
+ projectId: PROJECT_ID,
204
+ trialEndsAt: newTrialEndDate,
205
+ });
206
+
207
+ expect(hasPaymentMethods).not.toHaveBeenCalled();
208
+ });
209
+
210
+ it("should call the payment provider before writing the project row", async () => {
211
+ const callOrder: Array<string> = [];
212
+
213
+ jest
214
+ .spyOn(ProjectService, "findOneById")
215
+ .mockResolvedValue(fakeProject());
216
+ jest
217
+ .spyOn(BillingService, "getSubscriptionStatus")
218
+ .mockResolvedValue(SubscriptionStatus.Trialing as never);
219
+
220
+ jest.spyOn(BillingService, "extendTrial").mockImplementation((():
221
+ | Promise<void>
222
+ | undefined => {
223
+ callOrder.push("stripe");
224
+ return Promise.resolve();
225
+ }) as never);
226
+
227
+ jest.spyOn(ProjectService, "updateOneById").mockImplementation((():
228
+ | Promise<void>
229
+ | undefined => {
230
+ callOrder.push("database");
231
+ return Promise.resolve();
232
+ }) as never);
233
+
234
+ await ProjectService.extendTrial({
235
+ projectId: PROJECT_ID,
236
+ trialEndsAt: newTrialEndDate,
237
+ });
238
+
239
+ expect(callOrder).toEqual(["stripe", "database"]);
240
+ });
241
+
242
+ it("should not write to the project row when the payment provider rejects", async () => {
243
+ /*
244
+ * If Stripe refuses, the stored trial date has to stay put - otherwise
245
+ * the customer sees a trial in the dashboard that they are actually
246
+ * being billed for.
247
+ */
248
+ const spies: ExtendTrialSpies = setup({
249
+ extendTrialError: new Error("Stripe API error"),
250
+ });
251
+
252
+ await expect(
253
+ ProjectService.extendTrial({
254
+ projectId: PROJECT_ID,
255
+ trialEndsAt: newTrialEndDate,
256
+ }),
257
+ ).rejects.toThrow("Stripe API error");
258
+
259
+ expect(spies.updateOneById).not.toHaveBeenCalled();
260
+ });
261
+ });
262
+
263
+ describe("persisting the result", () => {
264
+ it("should persist the trial date with isRoot and ignoreHooks", async () => {
265
+ /*
266
+ * Project.trialEndsAt has an empty update ACL, so nothing but a root
267
+ * write can set it. ignoreHooks matches how changePlan persists.
268
+ */
269
+ const spies: ExtendTrialSpies = setup();
270
+
271
+ await ProjectService.extendTrial({
272
+ projectId: PROJECT_ID,
273
+ trialEndsAt: newTrialEndDate,
274
+ });
275
+
276
+ expect(spies.updateOneById).toHaveBeenCalledWith({
277
+ id: PROJECT_ID,
278
+ data: {
279
+ trialEndsAt: newTrialEndDate,
280
+ paymentProviderSubscriptionStatus: SubscriptionStatus.Trialing,
281
+ paymentProviderMeteredSubscriptionStatus: SubscriptionStatus.Trialing,
282
+ },
283
+ props: {
284
+ isRoot: true,
285
+ ignoreHooks: true,
286
+ },
287
+ });
288
+ });
289
+
290
+ it("should read both subscription statuses back from the payment provider", async () => {
291
+ const spies: ExtendTrialSpies = setup();
292
+
293
+ await ProjectService.extendTrial({
294
+ projectId: PROJECT_ID,
295
+ trialEndsAt: newTrialEndDate,
296
+ });
297
+
298
+ expect(spies.getSubscriptionStatus).toHaveBeenCalledWith(SUBSCRIPTION_ID);
299
+ expect(spies.getSubscriptionStatus).toHaveBeenCalledWith(
300
+ METERED_SUBSCRIPTION_ID,
301
+ );
302
+ });
303
+
304
+ it("should persist whatever statuses the payment provider reports", async () => {
305
+ /*
306
+ * The statuses are read back rather than assumed to be Trialing: the
307
+ * project row drives the customer's trial banner and the paywall, so it
308
+ * has to match Stripe even when Stripe disagrees with what we expected.
309
+ */
310
+ const spies: ExtendTrialSpies = setup();
311
+
312
+ spies.getSubscriptionStatus
313
+ .mockResolvedValueOnce(SubscriptionStatus.Trialing as never)
314
+ .mockResolvedValueOnce(SubscriptionStatus.Active as never);
315
+
316
+ await ProjectService.extendTrial({
317
+ projectId: PROJECT_ID,
318
+ trialEndsAt: newTrialEndDate,
319
+ });
320
+
321
+ expect(spies.updateOneById).toHaveBeenCalledWith(
322
+ expect.objectContaining({
323
+ data: {
324
+ trialEndsAt: newTrialEndDate,
325
+ paymentProviderSubscriptionStatus: SubscriptionStatus.Trialing,
326
+ paymentProviderMeteredSubscriptionStatus: SubscriptionStatus.Active,
327
+ },
328
+ }),
329
+ );
330
+ });
331
+ });
332
+ });
333
+
334
+ const CUSTOMER_ID: string = "cus_789";
335
+ const PLAN_ID: string = "monthly_growth_plan_id";
336
+ const REACTIVATED_SUBSCRIPTION_ID: string = "sub_main_new_789";
337
+ const REACTIVATED_METERED_SUBSCRIPTION_ID: string = "sub_metered_new_012";
338
+
339
+ function fakeReactivationProject(overrides?: Record<string, unknown>): Project {
340
+ return {
341
+ id: PROJECT_ID,
342
+ _id: PROJECT_ID.toString(),
343
+ trialEndsAt: OneUptimeDate.getSomeDaysAfter(20),
344
+ paymentProviderCustomerId: CUSTOMER_ID,
345
+ paymentProviderSubscriptionId: SUBSCRIPTION_ID,
346
+ paymentProviderMeteredSubscriptionId: METERED_SUBSCRIPTION_ID,
347
+ paymentProviderSubscriptionSeats: 4,
348
+ paymentProviderPlanId: PLAN_ID,
349
+ ...overrides,
350
+ } as unknown as Project;
351
+ }
352
+
353
+ /*
354
+ * reactiveSubscription puts a project back on its plan after payment recovers.
355
+ * It goes through BillingService.changePlan, which cancels both subscriptions
356
+ * and creates replacements - so a trial the project still has to run exists
357
+ * only if it is handed to those replacements and then written back.
358
+ *
359
+ * These tests pin that, because dropping it bills a customer whose trial a
360
+ * master admin extended as a goodwill gesture on the spot.
361
+ */
362
+ describe("ProjectService.reactiveSubscription", () => {
363
+ afterEach(() => {
364
+ jest.restoreAllMocks();
365
+ });
366
+
367
+ interface ReactivationSpies {
368
+ findOneById: jest.SpyInstance;
369
+ changePlan: jest.SpyInstance;
370
+ getSubscriptionStatus: jest.SpyInstance;
371
+ updateOneById: jest.SpyInstance;
372
+ }
373
+
374
+ function setupReactivation(data?: {
375
+ project?: Project;
376
+
377
+ /*
378
+ * The trial the payment provider reports on the subscriptions it created.
379
+ * Omitted means it reported none.
380
+ */
381
+ billingTrialEndsAt?: Date | undefined;
382
+ }): ReactivationSpies {
383
+ const findOneById: jest.SpyInstance = jest
384
+ .spyOn(ProjectService, "findOneById")
385
+ .mockResolvedValue(data?.project || fakeReactivationProject());
386
+
387
+ jest
388
+ .spyOn(SubscriptionPlan, "getSubscriptionPlanById")
389
+ .mockReturnValue(
390
+ new SubscriptionPlan(
391
+ PLAN_ID,
392
+ "yearly_growth_plan_id",
393
+ "Growth",
394
+ 25,
395
+ 250,
396
+ 2,
397
+ 14,
398
+ ),
399
+ );
400
+
401
+ const changePlan: jest.SpyInstance = jest
402
+ .spyOn(BillingService, "changePlan")
403
+ .mockResolvedValue({
404
+ subscriptionId: REACTIVATED_SUBSCRIPTION_ID,
405
+ meteredSubscriptionId: REACTIVATED_METERED_SUBSCRIPTION_ID,
406
+ trialEndsAt: data?.billingTrialEndsAt,
407
+ } as never);
408
+
409
+ const getSubscriptionStatus: jest.SpyInstance = jest
410
+ .spyOn(BillingService, "getSubscriptionStatus")
411
+ .mockResolvedValue(SubscriptionStatus.Active as never);
412
+
413
+ const updateOneById: jest.SpyInstance = jest
414
+ .spyOn(ProjectService, "updateOneById")
415
+ .mockResolvedValue(undefined as never);
416
+
417
+ return { findOneById, changePlan, getSubscriptionStatus, updateOneById };
418
+ }
419
+
420
+ function getUpdatedData(spies: ReactivationSpies): Record<string, unknown> {
421
+ return (
422
+ spies.updateOneById.mock.calls[0]![0] as {
423
+ data: Record<string, unknown>;
424
+ }
425
+ ).data;
426
+ }
427
+
428
+ describe("reading the project", () => {
429
+ it("should select the trial date", async () => {
430
+ /*
431
+ * Without this column in the select the trial date reads back undefined
432
+ * and every extension is silently dropped - which is the bug this
433
+ * suite exists for.
434
+ */
435
+ const spies: ReactivationSpies = setupReactivation();
436
+
437
+ await ProjectService.reactiveSubscription(PROJECT_ID);
438
+
439
+ expect(spies.findOneById).toHaveBeenCalledWith(
440
+ expect.objectContaining({
441
+ select: expect.objectContaining({
442
+ trialEndsAt: true,
443
+ }),
444
+ }),
445
+ );
446
+ });
447
+ });
448
+
449
+ describe("carrying the trial onto the new subscriptions", () => {
450
+ it("should send a trial that is still running as endTrialAt", async () => {
451
+ const trialEndsAt: Date = OneUptimeDate.getSomeDaysAfter(30);
452
+
453
+ const spies: ReactivationSpies = setupReactivation({
454
+ project: fakeReactivationProject({ trialEndsAt: trialEndsAt }),
455
+ });
456
+
457
+ await ProjectService.reactiveSubscription(PROJECT_ID);
458
+
459
+ expect(spies.changePlan).toHaveBeenCalledWith(
460
+ expect.objectContaining({
461
+ endTrialAt: trialEndsAt,
462
+ }),
463
+ );
464
+ });
465
+
466
+ it("should not send a trial that has already lapsed", async () => {
467
+ /*
468
+ * Reactivation is not the place to hand out free service: a project
469
+ * whose trial ran out months ago goes back onto its plan billing.
470
+ */
471
+ const spies: ReactivationSpies = setupReactivation({
472
+ project: fakeReactivationProject({
473
+ trialEndsAt: OneUptimeDate.getSomeDaysAgo(30),
474
+ }),
475
+ });
476
+
477
+ await ProjectService.reactiveSubscription(PROJECT_ID);
478
+
479
+ expect(spies.changePlan).toHaveBeenCalledWith(
480
+ expect.objectContaining({
481
+ endTrialAt: undefined,
482
+ }),
483
+ );
484
+ });
485
+
486
+ it("should not send a trial when the project has none", async () => {
487
+ const spies: ReactivationSpies = setupReactivation({
488
+ project: fakeReactivationProject({ trialEndsAt: null }),
489
+ });
490
+
491
+ await ProjectService.reactiveSubscription(PROJECT_ID);
492
+
493
+ expect(spies.changePlan).toHaveBeenCalledWith(
494
+ expect.objectContaining({
495
+ endTrialAt: undefined,
496
+ }),
497
+ );
498
+ });
499
+ });
500
+
501
+ describe("persisting the result", () => {
502
+ it("should persist the trial date the payment provider reports", async () => {
503
+ /*
504
+ * The payment provider is what actually charges the customer, so the
505
+ * date it puts on the new subscriptions wins over the one requested.
506
+ */
507
+ const billingTrialEndsAt: Date = OneUptimeDate.getSomeDaysAfter(45);
508
+
509
+ const spies: ReactivationSpies = setupReactivation({
510
+ project: fakeReactivationProject({
511
+ trialEndsAt: OneUptimeDate.getSomeDaysAfter(20),
512
+ }),
513
+ billingTrialEndsAt: billingTrialEndsAt,
514
+ });
515
+
516
+ await ProjectService.reactiveSubscription(PROJECT_ID);
517
+
518
+ expect(getUpdatedData(spies)["trialEndsAt"]).toEqual(billingTrialEndsAt);
519
+ });
520
+
521
+ it("should fall back to the trial it sent when the provider reports none", async () => {
522
+ const trialEndsAt: Date = OneUptimeDate.getSomeDaysAfter(30);
523
+
524
+ const spies: ReactivationSpies = setupReactivation({
525
+ project: fakeReactivationProject({ trialEndsAt: trialEndsAt }),
526
+ });
527
+
528
+ await ProjectService.reactiveSubscription(PROJECT_ID);
529
+
530
+ expect(getUpdatedData(spies)["trialEndsAt"]).toEqual(trialEndsAt);
531
+ });
532
+
533
+ it("should leave the stored trial date alone when there is no trial", async () => {
534
+ /*
535
+ * A project that stopped trialing long ago keeps the date it ended on
536
+ * rather than being stamped with a fresh one by an unrelated
537
+ * reactivation.
538
+ */
539
+ const spies: ReactivationSpies = setupReactivation({
540
+ project: fakeReactivationProject({
541
+ trialEndsAt: OneUptimeDate.getSomeDaysAgo(30),
542
+ }),
543
+ });
544
+
545
+ await ProjectService.reactiveSubscription(PROJECT_ID);
546
+
547
+ expect(Object.keys(getUpdatedData(spies))).not.toContain("trialEndsAt");
548
+ });
549
+
550
+ it("should still persist the new subscription ids and statuses", async () => {
551
+ const spies: ReactivationSpies = setupReactivation();
552
+
553
+ spies.getSubscriptionStatus
554
+ .mockResolvedValueOnce(SubscriptionStatus.Trialing as never)
555
+ .mockResolvedValueOnce(SubscriptionStatus.Active as never);
556
+
557
+ await ProjectService.reactiveSubscription(PROJECT_ID);
558
+
559
+ expect(getUpdatedData(spies)).toEqual(
560
+ expect.objectContaining({
561
+ paymentProviderSubscriptionId: REACTIVATED_SUBSCRIPTION_ID,
562
+ paymentProviderMeteredSubscriptionId:
563
+ REACTIVATED_METERED_SUBSCRIPTION_ID,
564
+ paymentProviderSubscriptionStatus: SubscriptionStatus.Trialing,
565
+ paymentProviderMeteredSubscriptionStatus: SubscriptionStatus.Active,
566
+ }),
567
+ );
568
+ });
569
+
570
+ it("should write the project row as root", async () => {
571
+ // Project.trialEndsAt has an empty update ACL - only a root write sets it.
572
+ const spies: ReactivationSpies = setupReactivation();
573
+
574
+ await ProjectService.reactiveSubscription(PROJECT_ID);
575
+
576
+ expect(spies.updateOneById).toHaveBeenCalledWith(
577
+ expect.objectContaining({
578
+ id: PROJECT_ID,
579
+ props: {
580
+ isRoot: true,
581
+ },
582
+ }),
583
+ );
584
+ });
585
+ });
586
+
587
+ describe("the goodwill extension it exists to protect", () => {
588
+ it("should keep an extended trial across a reactivation", async () => {
589
+ /*
590
+ * The end-to-end shape of the bug: support extends a customer's trial,
591
+ * their subscription is later reactivated, and the extension has to
592
+ * still be there afterwards - on the new subscriptions and on the row.
593
+ */
594
+ const extendedTrialEndsAt: Date = OneUptimeDate.getSomeDaysAfter(60);
595
+
596
+ const spies: ReactivationSpies = setupReactivation({
597
+ project: fakeReactivationProject({
598
+ trialEndsAt: extendedTrialEndsAt,
599
+ }),
600
+ billingTrialEndsAt: extendedTrialEndsAt,
601
+ });
602
+
603
+ await ProjectService.reactiveSubscription(PROJECT_ID);
604
+
605
+ expect(spies.changePlan).toHaveBeenCalledWith(
606
+ expect.objectContaining({
607
+ endTrialAt: extendedTrialEndsAt,
608
+ }),
609
+ );
610
+
611
+ expect(getUpdatedData(spies)["trialEndsAt"]).toEqual(extendedTrialEndsAt);
612
+ });
613
+ });
614
+ });