@oneuptime/common 12.0.4 → 12.0.5

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 (374) hide show
  1. package/Models/DatabaseModels/AIRun.ts +38 -1
  2. package/Models/DatabaseModels/AlertFeed.ts +30 -0
  3. package/Models/DatabaseModels/Dashboard.ts +28 -0
  4. package/Models/DatabaseModels/Incident.ts +2 -0
  5. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  6. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  7. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  8. package/Models/DatabaseModels/IncidentFeed.ts +30 -0
  9. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  10. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  11. package/Models/DatabaseModels/LogSavedView.ts +33 -0
  12. package/Models/DatabaseModels/Project.ts +231 -9
  13. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  14. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  15. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  16. package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +4 -4
  17. package/Models/DatabaseModels/StatusPage.ts +28 -0
  18. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  19. package/Server/API/AIAgentDataAPI.ts +44 -55
  20. package/Server/API/AIInvestigationAPI.ts +175 -17
  21. package/Server/API/DashboardAPI.ts +10 -10
  22. package/Server/API/StatusPageAPI.ts +38 -19
  23. package/Server/EnvironmentConfig.ts +16 -0
  24. package/Server/Infrastructure/ClickhouseConfig.ts +15 -1
  25. package/Server/Infrastructure/ClickhouseDatabase.ts +1 -1
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.ts +27 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.ts +89 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.ts +27 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.ts +40 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.ts +26 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  32. package/Server/Services/AIRunService.ts +78 -10
  33. package/Server/Services/AIService.ts +94 -22
  34. package/Server/Services/AlertFeedService.ts +5 -0
  35. package/Server/Services/AnalyticsDatabaseService.ts +29 -0
  36. package/Server/Services/DatabaseService.ts +43 -2
  37. package/Server/Services/IncidentFeedService.ts +5 -0
  38. package/Server/Services/LlmLogService.ts +46 -2
  39. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +6 -0
  40. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +4 -0
  41. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +8 -5
  42. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +90 -16
  43. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +2 -0
  44. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +2 -0
  45. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +223 -22
  46. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +25 -24
  47. package/Server/Utils/AI/SRE/ConfidenceSignal.ts +182 -71
  48. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +252 -43
  49. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +25 -24
  50. package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +47 -13
  51. package/Server/Utils/AI/SRE/InvestigationGrader.ts +9 -5
  52. package/Server/Utils/AI/SRE/InvestigationQueue.ts +141 -24
  53. package/Server/Utils/AI/SRE/InvestigationSubjectLock.ts +66 -0
  54. package/Server/Utils/AI/SRE/PostedRootCause.ts +94 -3
  55. package/Server/Utils/AI/SRE/README.md +1 -1
  56. package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +132 -10
  57. package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +24 -0
  58. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +29 -0
  59. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +56 -0
  60. package/Server/Utils/Monitor/MonitorMetricUtil.ts +46 -0
  61. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
  62. package/Server/Utils/PasswordHash.ts +28 -4
  63. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +251 -0
  64. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +747 -0
  65. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +480 -0
  66. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1184 -0
  67. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +500 -0
  68. package/Tests/App/Dashboard/PortMonitorCriteriaFilter.test.ts +93 -0
  69. package/Tests/App/StatusPage/PublicStatusPageAPIErrorHandling.test.ts +117 -0
  70. package/Tests/App/StatusPage/StatusPageModelAPIPolymorphism.test.ts +223 -0
  71. package/Tests/Models/DatabaseModels/PermissionCatalogueCoverage.test.ts +243 -0
  72. package/Tests/Server/API/AIAgentDataFixFromIncidentContext.test.ts +266 -0
  73. package/Tests/Server/API/AIInvestigationAPI.test.ts +594 -0
  74. package/Tests/Server/API/AIInvestigationCreateFixTask.test.ts +80 -0
  75. package/Tests/Server/API/DashboardMasterPasswordAPI.test.ts +172 -1
  76. package/Tests/Server/API/StatusPageMasterPasswordAPI.test.ts +335 -0
  77. package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +59 -5
  78. package/Tests/Server/Services/AIRunHumanVerdict.test.ts +127 -58
  79. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +396 -20
  80. package/Tests/Server/Services/AddMasterPasswordSaltMigration.test.ts +283 -0
  81. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +25 -1
  82. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +45 -35
  83. package/Tests/Server/Services/DatabaseServiceUpdateColumnsWithoutHooks.test.ts +54 -0
  84. package/Tests/Server/Services/FeedAIRunAssociation.test.ts +125 -0
  85. package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +418 -57
  86. package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +173 -14
  87. package/Tests/Server/Services/MasterPasswordScrypt.test.ts +567 -0
  88. package/Tests/Server/Services/SeparateIncidentAlertAiSettingsMigration.test.ts +194 -0
  89. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +37 -4
  90. package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +330 -29
  91. package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +25 -0
  92. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +293 -5
  93. package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +59 -1
  94. package/Tests/Server/Utils/AI/FixFromIncidentAutoTrigger.test.ts +342 -19
  95. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +214 -30
  96. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +2 -0
  97. package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +65 -17
  98. package/Tests/Server/Utils/AI/InvestigationQueueRemediationExecution.test.ts +3 -0
  99. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +313 -20
  100. package/Tests/Server/Utils/AI/PostedRootCause.test.ts +254 -0
  101. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +4 -0
  102. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +2 -0
  103. package/Tests/Server/Utils/AI/SubjectCodeFixRunDedupe.test.ts +44 -0
  104. package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +30 -0
  105. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +212 -0
  106. package/Tests/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.test.ts +401 -0
  107. package/Tests/Server/Utils/Monitor/MonitorMetricUtilPortTimings.test.ts +243 -0
  108. package/Tests/Server/Utils/PasswordHash.test.ts +30 -0
  109. package/Tests/Types/Dashboard/DashboardTemplates.test.ts +111 -0
  110. package/Tests/Types/Monitor/CephMetricCatalog.test.ts +104 -0
  111. package/Tests/Types/Monitor/CriteriaFilter.test.ts +4 -0
  112. package/Tests/Types/Monitor/DockerMetricCatalog.test.ts +109 -0
  113. package/Tests/Types/Monitor/DockerSwarmMetricCatalog.test.ts +118 -0
  114. package/Tests/Types/Monitor/HostMetricCatalog.test.ts +104 -0
  115. package/Tests/Types/Monitor/IotMetricCatalog.test.ts +104 -0
  116. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +118 -0
  117. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +42 -0
  118. package/Tests/Types/Monitor/MonitorStep.test.ts +38 -0
  119. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +75 -0
  120. package/Tests/Types/Monitor/PodmanMetricCatalog.test.ts +109 -0
  121. package/Tests/Types/Monitor/ProxmoxMetricCatalog.test.ts +107 -0
  122. package/Tests/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.test.ts +151 -0
  123. package/Tests/Types/Permission.test.ts +137 -0
  124. package/Tests/Types/Rum/SessionReplayMaskingMode.test.ts +101 -0
  125. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +5 -5
  126. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +3 -5
  127. package/Tests/UI/Components/ErrorBoundary.test.tsx +158 -0
  128. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +74 -0
  129. package/Tests/UI/Components/MoreMenu.test.tsx +756 -0
  130. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +62 -0
  131. package/Tests/UI/Monitor/PortMonitorView.test.tsx +237 -0
  132. package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +91 -0
  133. package/Tests/UI/Utils/DownloadFile.test.ts +103 -0
  134. package/Tests/UI/Utils/ErrorSupportBundle.test.ts +582 -0
  135. package/Tests/UI/Utils/Project.test.ts +31 -0
  136. package/Tests/UI/Utils/StatusPageModelAPIInjection.test.ts +245 -0
  137. package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +820 -0
  138. package/Tests/Utils/Dashboard/DashboardViewConfig.test.ts +329 -0
  139. package/Tests/Utils/Dashboard/GridLayout.test.ts +951 -0
  140. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +117 -0
  141. package/Tests/Utils/RecordingRuleExpression.test.ts +327 -0
  142. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +186 -0
  143. package/Tests/Utils/StatusPage/GroupTree.test.ts +456 -0
  144. package/Tests/Utils/StatusPage/OverviewGroupHierarchyVisibility.test.ts +588 -0
  145. package/Tests/Utils/Telemetry/SavedViewTimeRange.test.ts +244 -0
  146. package/Tests/Utils/Telemetry/TelemetryQueryTimeRange.test.ts +825 -0
  147. package/Types/AI/AIRunCodeFixRecommendation.ts +17 -0
  148. package/Types/AI/CodeFixTaskContext.ts +63 -3
  149. package/Types/AI/CodeFixTaskType.ts +3 -3
  150. package/Types/HashedString.ts +4 -3
  151. package/Types/Monitor/CriteriaFilter.ts +4 -0
  152. package/Types/Monitor/DomainMonitor/DomainLookupMethod.ts +23 -0
  153. package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +7 -0
  154. package/Types/Monitor/MonitorCriteriaInstance.ts +24 -7
  155. package/Types/Monitor/MonitorMetricType.ts +8 -0
  156. package/Types/Monitor/MonitorStep.ts +10 -1
  157. package/Types/Monitor/MonitorStepDomainMonitor.ts +21 -0
  158. package/Types/Monitor/PortMonitor/PortMonitorTimings.ts +10 -0
  159. package/Types/Permission.ts +23 -175
  160. package/Types/Probe/ProbeMonitorResponse.ts +6 -0
  161. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +2 -3
  162. package/UI/Components/ErrorBoundary.tsx +138 -11
  163. package/UI/Components/Feed/FeedItem.tsx +9 -2
  164. package/UI/Components/ModelDetail/CardModelDetail.tsx +0 -12
  165. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  166. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +12 -2
  167. package/UI/Components/MoreMenu/MoreMenu.tsx +285 -97
  168. package/UI/Components/MoreMenu/MoreMenuItem.tsx +8 -5
  169. package/UI/Utils/DownloadFile.ts +16 -8
  170. package/UI/Utils/ErrorSupportBundle.ts +805 -0
  171. package/UI/Utils/ModelAPI/ModelAPI.ts +19 -8
  172. package/UI/Utils/Project.ts +4 -0
  173. package/UI/Utils/StatusPage.ts +8 -2
  174. package/UI/Utils/UseDashboardGridDnd.ts +917 -0
  175. package/Utils/Dashboard/DashboardViewConfig.ts +80 -36
  176. package/Utils/Dashboard/GridLayout.ts +523 -0
  177. package/Utils/Metrics/RecordingRuleExpression.ts +19 -17
  178. package/Utils/Monitor/MonitorMetricType.ts +44 -2
  179. package/Utils/StatusPage/GroupNestingLayout.ts +69 -0
  180. package/Utils/StatusPage/GroupTree.ts +157 -66
  181. package/Utils/StatusPage/ResourceUptime.ts +37 -2
  182. package/Utils/Telemetry/SavedViewTimeRange.ts +114 -0
  183. package/Utils/Telemetry/TelemetryQueryTimeRange.ts +334 -0
  184. package/build/dist/Models/DatabaseModels/AIRun.js +39 -1
  185. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/AlertFeed.js +32 -0
  187. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/Dashboard.js +29 -0
  189. package/build/dist/Models/DatabaseModels/Dashboard.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  191. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  193. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  195. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.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/IncidentFeed.js +32 -0
  199. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  201. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  203. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/LogSavedView.js +33 -0
  205. package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/Project.js +241 -11
  207. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  209. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  211. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  212. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  213. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  214. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +4 -4
  215. package/build/dist/Models/DatabaseModels/StatusPage.js +29 -0
  216. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  218. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  219. package/build/dist/Server/API/AIAgentDataAPI.js +28 -46
  220. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  221. package/build/dist/Server/API/AIInvestigationAPI.js +111 -11
  222. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  223. package/build/dist/Server/API/DashboardAPI.js +8 -5
  224. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  225. package/build/dist/Server/API/StatusPageAPI.js +29 -11
  226. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  227. package/build/dist/Server/EnvironmentConfig.js +14 -0
  228. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  229. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +12 -1
  230. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  231. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +1 -1
  232. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
  233. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js +22 -0
  234. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js.map +1 -0
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js +36 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js.map +1 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js +18 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js.map +1 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js +19 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js.map +1 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js +19 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js.map +1 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  245. package/build/dist/Server/Services/AIRunService.js +58 -12
  246. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  247. package/build/dist/Server/Services/AIService.js +74 -21
  248. package/build/dist/Server/Services/AIService.js.map +1 -1
  249. package/build/dist/Server/Services/AlertFeedService.js +3 -0
  250. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  251. package/build/dist/Server/Services/AnalyticsDatabaseService.js +29 -1
  252. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  253. package/build/dist/Server/Services/DatabaseService.js +21 -2
  254. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  255. package/build/dist/Server/Services/IncidentFeedService.js +3 -0
  256. package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
  257. package/build/dist/Server/Services/LlmLogService.js +22 -1
  258. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  259. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  260. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  261. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +4 -0
  262. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
  263. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +8 -5
  264. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  265. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +63 -24
  266. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  267. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +2 -0
  268. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  269. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +2 -0
  270. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  271. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +156 -28
  272. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  273. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +21 -19
  274. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  275. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +128 -49
  276. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -1
  277. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +170 -31
  278. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -1
  279. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +21 -19
  280. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  281. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +33 -9
  282. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -1
  283. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +9 -5
  284. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -1
  285. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +121 -41
  286. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  287. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js +46 -0
  288. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js.map +1 -0
  289. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js +61 -14
  290. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js.map +1 -1
  291. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +79 -1
  292. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
  293. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +21 -0
  294. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
  295. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +20 -3
  296. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  297. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +43 -0
  298. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
  299. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  300. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  301. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
  302. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  303. package/build/dist/Server/Utils/PasswordHash.js +25 -4
  304. package/build/dist/Server/Utils/PasswordHash.js.map +1 -1
  305. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js +18 -0
  306. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js.map +1 -0
  307. package/build/dist/Types/AI/CodeFixTaskContext.js +23 -3
  308. package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
  309. package/build/dist/Types/AI/CodeFixTaskType.js +3 -3
  310. package/build/dist/Types/HashedString.js +4 -3
  311. package/build/dist/Types/HashedString.js.map +1 -1
  312. package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
  313. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  314. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js +24 -0
  315. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js.map +1 -0
  316. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +24 -7
  317. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  318. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  319. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  320. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  321. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  322. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +15 -0
  323. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
  324. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js +2 -0
  325. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js.map +1 -0
  326. package/build/dist/Types/Permission.js +23 -155
  327. package/build/dist/Types/Permission.js.map +1 -1
  328. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +2 -5
  329. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  330. package/build/dist/UI/Components/ErrorBoundary.js +67 -8
  331. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  332. package/build/dist/UI/Components/Feed/FeedItem.js +2 -2
  333. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  334. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +0 -12
  335. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  336. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  337. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  338. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +12 -2
  339. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  340. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +193 -65
  341. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  342. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +1 -1
  343. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  344. package/build/dist/UI/Utils/DownloadFile.js +15 -8
  345. package/build/dist/UI/Utils/DownloadFile.js.map +1 -1
  346. package/build/dist/UI/Utils/ErrorSupportBundle.js +476 -0
  347. package/build/dist/UI/Utils/ErrorSupportBundle.js.map +1 -0
  348. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -8
  349. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  350. package/build/dist/UI/Utils/Project.js +3 -0
  351. package/build/dist/UI/Utils/Project.js.map +1 -1
  352. package/build/dist/UI/Utils/StatusPage.js +4 -4
  353. package/build/dist/UI/Utils/StatusPage.js.map +1 -1
  354. package/build/dist/UI/Utils/UseDashboardGridDnd.js +551 -0
  355. package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -0
  356. package/build/dist/Utils/Dashboard/DashboardViewConfig.js +42 -26
  357. package/build/dist/Utils/Dashboard/DashboardViewConfig.js.map +1 -1
  358. package/build/dist/Utils/Dashboard/GridLayout.js +338 -0
  359. package/build/dist/Utils/Dashboard/GridLayout.js.map +1 -0
  360. package/build/dist/Utils/Metrics/RecordingRuleExpression.js +19 -17
  361. package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -1
  362. package/build/dist/Utils/Monitor/MonitorMetricType.js +38 -6
  363. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  364. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +46 -0
  365. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -1
  366. package/build/dist/Utils/StatusPage/GroupTree.js +79 -34
  367. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -1
  368. package/build/dist/Utils/StatusPage/ResourceUptime.js +22 -1
  369. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  370. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js +79 -0
  371. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js.map +1 -0
  372. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js +236 -0
  373. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js.map +1 -0
  374. package/package.json +1 -1
@@ -0,0 +1,582 @@
1
+ import downloadFile from "../../../UI/Utils/DownloadFile";
2
+ import {
3
+ ERROR_SUPPORT_BUNDLE_SCHEMA_VERSION,
4
+ ErrorSupportBundle,
5
+ ErrorSupportBundleRuntimeDetails,
6
+ SerializedSupportError,
7
+ MAX_SUPPORT_COMPONENT_STACK_LENGTH,
8
+ MAX_SUPPORT_ERROR_MESSAGE_LENGTH,
9
+ MAX_SUPPORT_ERROR_STACK_LENGTH,
10
+ collectErrorSupportBundleRuntimeDetails,
11
+ createErrorSupportBundle,
12
+ downloadErrorSupportBundle,
13
+ getComponentFromStack,
14
+ getErrorSupportBundleFilename,
15
+ redactSensitiveSupportText,
16
+ scrubUrlsInSupportText,
17
+ serializeSupportError,
18
+ } from "../../../UI/Utils/ErrorSupportBundle";
19
+
20
+ jest.mock("../../../UI/Utils/DownloadFile", () => {
21
+ return {
22
+ __esModule: true,
23
+ default: jest.fn(),
24
+ };
25
+ });
26
+
27
+ const downloadFileMock: jest.MockedFunction<typeof downloadFile> =
28
+ downloadFile as jest.MockedFunction<typeof downloadFile>;
29
+
30
+ function getRuntimeDetails(): ErrorSupportBundleRuntimeDetails {
31
+ return {
32
+ application: {
33
+ appVersion: "8.2.1",
34
+ gitSha: "0123456789abcdef",
35
+ edition: "Enterprise",
36
+ nodeEnvironment: "production",
37
+ reactVersion: "18.3.1",
38
+ },
39
+ page: {
40
+ url: "https://oneuptime.example/dashboard/traces",
41
+ pathname: "/dashboard/traces",
42
+ documentTitle: "Traces | OneUptime",
43
+ hadQueryString: true,
44
+ hadFragment: false,
45
+ visibilityState: "visible",
46
+ documentReadyState: "complete",
47
+ historyLength: 4,
48
+ },
49
+ browser: {
50
+ userAgent: "Test Browser/1.0",
51
+ platform: "Test OS",
52
+ vendor: "Test Vendor",
53
+ language: "en-GB",
54
+ languages: ["en-GB", "en"],
55
+ onLine: true,
56
+ cookieEnabled: true,
57
+ hardwareConcurrency: 8,
58
+ maxTouchPoints: 2,
59
+ timeZone: "Europe/London",
60
+ timeZoneOffsetMinutes: -60,
61
+ },
62
+ display: {
63
+ viewportWidth: 1440,
64
+ viewportHeight: 900,
65
+ screenWidth: 2560,
66
+ screenHeight: 1440,
67
+ availableScreenWidth: 2560,
68
+ availableScreenHeight: 1400,
69
+ devicePixelRatio: 2,
70
+ colorDepth: 24,
71
+ pixelDepth: 24,
72
+ },
73
+ serviceWorker: {
74
+ isSupported: true,
75
+ isControlled: true,
76
+ scriptUrl: "https://oneuptime.example/sw.js",
77
+ state: "activated",
78
+ },
79
+ navigation: {
80
+ type: "navigate",
81
+ durationInMilliseconds: 1250,
82
+ domContentLoadedInMilliseconds: 900,
83
+ pageLoadInMilliseconds: 1200,
84
+ transferSizeInBytes: 1024,
85
+ encodedBodySizeInBytes: 900,
86
+ decodedBodySizeInBytes: 2400,
87
+ serviceWorkerStartInMilliseconds: 5,
88
+ },
89
+ };
90
+ }
91
+
92
+ describe("createErrorSupportBundle", () => {
93
+ test("creates a structured diagnostic snapshot with the error and runtime context", () => {
94
+ const cause: Error = new Error("Database connection closed");
95
+ const error: Error = new Error("Unable to render trace chart");
96
+ error.stack =
97
+ "Error: Unable to render trace chart\n at TraceChart (chart.tsx:42:7)";
98
+ Object.defineProperty(error, "cause", { value: cause });
99
+ Object.assign(error, {
100
+ code: "TRACE_RENDER_FAILED",
101
+ status: 500,
102
+ statusCode: 502,
103
+ });
104
+
105
+ const bundle: ErrorSupportBundle = createErrorSupportBundle({
106
+ error: error,
107
+ componentStack:
108
+ "\n at TraceChart (chart.tsx:42:7)\n at TracesPage (Traces.tsx:20:3)",
109
+ digest: "react-digest-1",
110
+ capturedAt: "2026-08-07T11:59:58.000Z",
111
+ generatedAt: new Date("2026-08-07T12:00:00.000Z"),
112
+ runtimeDetails: getRuntimeDetails(),
113
+ });
114
+
115
+ expect(bundle.schemaVersion).toBe(ERROR_SUPPORT_BUNDLE_SCHEMA_VERSION);
116
+ expect(bundle.type).toBe("oneuptime-browser-error");
117
+ expect(bundle.generatedAt).toBe("2026-08-07T12:00:00.000Z");
118
+ expect(bundle.errorCapturedAt).toBe("2026-08-07T11:59:58.000Z");
119
+ expect(bundle.application.appVersion).toBe("8.2.1");
120
+ expect(bundle.application.gitSha).toBe("0123456789abcdef");
121
+ expect(bundle.error.name).toBe("Error");
122
+ expect(bundle.error.message).toBe("Unable to render trace chart");
123
+ expect(bundle.error.stack).toContain("TraceChart");
124
+ expect(bundle.error.code).toBe("TRACE_RENDER_FAILED");
125
+ expect(bundle.error.status).toBe(500);
126
+ expect(bundle.error.statusCode).toBe(502);
127
+ expect(bundle.error.cause?.message).toBe("Database connection closed");
128
+ expect(bundle.react.component).toBe("TraceChart");
129
+ expect(bundle.react.componentStack).toContain("TracesPage");
130
+ expect(bundle.react.digest).toBe("react-digest-1");
131
+ expect(bundle.page.url).toBe("https://oneuptime.example/dashboard/traces");
132
+ expect(bundle.browser.timeZone).toBe("Europe/London");
133
+ expect(bundle.display.devicePixelRatio).toBe(2);
134
+ expect(bundle.serviceWorker.state).toBe("activated");
135
+ expect(bundle.navigation?.transferSizeInBytes).toBe(1024);
136
+ });
137
+
138
+ test("keeps Error fields that JSON.stringify(Error) normally loses", () => {
139
+ const error: Error = new TypeError("Cannot read queryConfigs");
140
+
141
+ expect(JSON.stringify(error)).toBe("{}");
142
+
143
+ const bundle: ErrorSupportBundle = createErrorSupportBundle({
144
+ error: error,
145
+ generatedAt: new Date("2026-08-07T12:00:00.000Z"),
146
+ runtimeDetails: getRuntimeDetails(),
147
+ });
148
+
149
+ expect(bundle.error.name).toBe("TypeError");
150
+ expect(bundle.error.message).toBe("Cannot read queryConfigs");
151
+ expect(bundle.error.stack).toContain("TypeError: Cannot read queryConfigs");
152
+ });
153
+
154
+ test("uses the generation time when the capture time is unavailable", () => {
155
+ const bundle: ErrorSupportBundle = createErrorSupportBundle({
156
+ error: new Error("Boom"),
157
+ generatedAt: new Date("2026-08-07T12:00:00.000Z"),
158
+ runtimeDetails: getRuntimeDetails(),
159
+ });
160
+
161
+ expect(bundle.errorCapturedAt).toBe(bundle.generatedAt);
162
+ });
163
+
164
+ test("supports errors without stacks or React component information", () => {
165
+ const error: Error = new Error("Stack unavailable");
166
+ delete error.stack;
167
+
168
+ const bundle: ErrorSupportBundle = createErrorSupportBundle({
169
+ error: error,
170
+ componentStack: null,
171
+ generatedAt: new Date("2026-08-07T12:00:00.000Z"),
172
+ runtimeDetails: getRuntimeDetails(),
173
+ });
174
+
175
+ expect(bundle.error.stack).toBeNull();
176
+ expect(bundle.react.component).toBeNull();
177
+ expect(bundle.react.componentStack).toBeNull();
178
+ expect(bundle.react.digest).toBeNull();
179
+ });
180
+
181
+ test("scrubs secrets from the page and absolute URLs in error stacks", () => {
182
+ const runtimeDetails: ErrorSupportBundleRuntimeDetails =
183
+ getRuntimeDetails();
184
+ runtimeDetails.page.url =
185
+ "https://oneuptime.example/reset-password/[redacted]";
186
+ runtimeDetails.page.pathname = "/reset-password/[redacted]";
187
+
188
+ const error: Error = new Error(
189
+ "Failed at https://oneuptime.example/verify?token=message-secret",
190
+ );
191
+ error.stack =
192
+ "Error: failed\n at submit (https://oneuptime.example/reset-password?token=stack-secret:12:5)";
193
+
194
+ const bundle: ErrorSupportBundle = createErrorSupportBundle({
195
+ error: error,
196
+ componentStack:
197
+ "\n at ResetPassword (https://oneuptime.example/reset-password?token=component-secret:9:2)",
198
+ generatedAt: new Date("2026-08-07T12:00:00.000Z"),
199
+ runtimeDetails: runtimeDetails,
200
+ });
201
+ const serialized: string = JSON.stringify(bundle);
202
+
203
+ expect(serialized).not.toContain("message-secret");
204
+ expect(serialized).not.toContain("stack-secret");
205
+ expect(serialized).not.toContain("component-secret");
206
+ expect(bundle.error.message).toContain("https://oneuptime.example/verify");
207
+ expect(bundle.error.stack).toContain(
208
+ "https://oneuptime.example/reset-password",
209
+ );
210
+ });
211
+
212
+ test("redacts common credentials and personal data from free-form fields", () => {
213
+ const error: Error = new Error(
214
+ "Authorization: Bearer abcdefghijklmnopqrstuvwxyz password=abc token=my-reset-token authToken=short credential=x Cookie: session=abc signature=sig alice@example.com",
215
+ );
216
+ error.stack =
217
+ "Error from postgres://admin:database-password@db.example.com/app";
218
+ Object.assign(error, {
219
+ code: "api_key=code-secret-value",
220
+ });
221
+
222
+ const bundle: ErrorSupportBundle = createErrorSupportBundle({
223
+ error: error,
224
+ digest: "Bearer digest-secret-value",
225
+ generatedAt: new Date("2026-08-07T12:00:00.000Z"),
226
+ runtimeDetails: getRuntimeDetails(),
227
+ });
228
+ const serialized: string = JSON.stringify(bundle);
229
+
230
+ expect(serialized).not.toContain("abcdefghijklmnopqrstuvwxyz");
231
+ expect(serialized).not.toContain("password=abc");
232
+ expect(serialized).not.toContain("my-reset-token");
233
+ expect(serialized).not.toContain("authToken=short");
234
+ expect(serialized).not.toContain("credential=x");
235
+ expect(serialized).not.toContain("session=abc");
236
+ expect(serialized).not.toContain("signature=sig");
237
+ expect(serialized).not.toContain("alice@example.com");
238
+ expect(serialized).not.toContain("database-password");
239
+ expect(serialized).not.toContain("code-secret-value");
240
+ expect(serialized).not.toContain("digest-secret-value");
241
+ expect(bundle.error.message).toContain("[redacted");
242
+ });
243
+
244
+ test("truncates pathological messages and stacks without losing the marker", () => {
245
+ const error: Error = new Error("m".repeat(20000));
246
+ error.stack = "s".repeat(50000);
247
+
248
+ const bundle: ErrorSupportBundle = createErrorSupportBundle({
249
+ error: error,
250
+ componentStack: "c".repeat(50000),
251
+ generatedAt: new Date("2026-08-07T12:00:00.000Z"),
252
+ runtimeDetails: getRuntimeDetails(),
253
+ });
254
+
255
+ expect(bundle.error.message.length).toBeLessThanOrEqual(
256
+ MAX_SUPPORT_ERROR_MESSAGE_LENGTH,
257
+ );
258
+ expect(bundle.error.stack?.length).toBeLessThanOrEqual(
259
+ MAX_SUPPORT_ERROR_STACK_LENGTH,
260
+ );
261
+ expect(bundle.react.componentStack?.length).toBeLessThanOrEqual(
262
+ MAX_SUPPORT_COMPONENT_STACK_LENGTH,
263
+ );
264
+ expect(bundle.error.message).toContain("[truncated]");
265
+ expect(bundle.error.stack).toContain("[truncated]");
266
+ expect(bundle.react.componentStack).toContain("[truncated]");
267
+ });
268
+
269
+ test("redacts oversized credentials before truncating diagnostics", () => {
270
+ const privateKeyMaterial: string = "a".repeat(
271
+ MAX_SUPPORT_ERROR_MESSAGE_LENGTH * 2,
272
+ );
273
+ const error: Error = new Error(
274
+ `-----BEGIN PRIVATE KEY-----\n${privateKeyMaterial}\n-----END PRIVATE KEY-----`,
275
+ );
276
+ error.stack = `Error: eyJ${"b".repeat(
277
+ MAX_SUPPORT_ERROR_STACK_LENGTH * 2,
278
+ )}.payload.signature`;
279
+
280
+ const serializedError: SerializedSupportError =
281
+ serializeSupportError(error);
282
+
283
+ expect(serializedError.message).toBe("[redacted-private-key]");
284
+ expect(serializedError.message).not.toContain(
285
+ privateKeyMaterial.slice(0, 100),
286
+ );
287
+ expect(serializedError.stack).toBe("Error: [redacted-jwt]");
288
+ });
289
+
290
+ test("documents the privacy contract in every bundle", () => {
291
+ const bundle: ErrorSupportBundle = createErrorSupportBundle({
292
+ error: new Error("Boom"),
293
+ generatedAt: new Date("2026-08-07T12:00:00.000Z"),
294
+ runtimeDetails: getRuntimeDetails(),
295
+ });
296
+
297
+ expect(bundle.privacy.reviewBeforeSharing).toContain("Review");
298
+ expect(bundle.privacy.urlHandling).toContain("Query strings");
299
+ expect(
300
+ bundle.privacy.excluded.some((item: string): boolean => {
301
+ return item.includes("local storage");
302
+ }),
303
+ ).toBe(true);
304
+ expect(
305
+ bundle.privacy.excluded.some((item: string): boolean => {
306
+ return item.includes("environment-variable");
307
+ }),
308
+ ).toBe(true);
309
+ });
310
+ });
311
+
312
+ describe("serializeSupportError", () => {
313
+ test.each([
314
+ ["a string", "render exploded", "render exploded"],
315
+ ["a number", 42, "42"],
316
+ ["null", null, "A null value was thrown."],
317
+ ["undefined", undefined, "An undefined value was thrown."],
318
+ ])(
319
+ "safely serializes %s throwable",
320
+ (_label: string, throwable: unknown, expectedMessage: string) => {
321
+ expect(serializeSupportError(throwable).message).toBe(expectedMessage);
322
+ },
323
+ );
324
+
325
+ test("does not serialize arbitrary custom properties or response bodies", () => {
326
+ const error: Error & { responseBody?: string } = new Error(
327
+ "Request failed",
328
+ );
329
+ error.responseBody = "customer-secret-response-body";
330
+
331
+ const serialized: string = JSON.stringify(serializeSupportError(error));
332
+
333
+ expect(serialized).not.toContain("customer-secret-response-body");
334
+ expect(serialized).not.toContain("responseBody");
335
+ });
336
+
337
+ test("survives hostile property getters", () => {
338
+ const throwable: Record<string, unknown> = {};
339
+
340
+ for (const propertyName of ["name", "message", "stack", "cause"]) {
341
+ Object.defineProperty(throwable, propertyName, {
342
+ configurable: true,
343
+ get: () => {
344
+ throw new Error("getter exploded");
345
+ },
346
+ });
347
+ }
348
+
349
+ expect(() => {
350
+ serializeSupportError(throwable);
351
+ }).not.toThrow();
352
+ expect(serializeSupportError(throwable).message).toBe(
353
+ "A non-Error value was thrown.",
354
+ );
355
+ });
356
+
357
+ test("survives an Error whose name getter throws", () => {
358
+ const error: Error = new Error("Boom");
359
+ Object.defineProperty(error, "name", {
360
+ configurable: true,
361
+ get: () => {
362
+ throw new Error("name getter exploded");
363
+ },
364
+ });
365
+
366
+ expect(serializeSupportError(error).name).toBe("Error");
367
+ });
368
+
369
+ test("normalizes non-finite diagnostic numbers before JSON serialization", () => {
370
+ const error: Error = new Error("Boom");
371
+ Object.assign(error, {
372
+ code: Number.NaN,
373
+ status: Number.POSITIVE_INFINITY,
374
+ statusCode: Number.NEGATIVE_INFINITY,
375
+ });
376
+
377
+ const serialized: SerializedSupportError = serializeSupportError(error);
378
+
379
+ expect(serialized.code).toBeNull();
380
+ expect(serialized.status).toBeNull();
381
+ expect(serialized.statusCode).toBeNull();
382
+ });
383
+
384
+ test("detects circular error causes", () => {
385
+ const error: Error = new Error("Root error");
386
+ Object.defineProperty(error, "cause", { value: error });
387
+
388
+ const serialized: SerializedSupportError = serializeSupportError(error);
389
+
390
+ expect(serialized.cause?.name).toBe("CircularErrorCause");
391
+ expect(() => {
392
+ JSON.stringify(serialized);
393
+ }).not.toThrow();
394
+ });
395
+
396
+ test("caps deeply nested cause chains", () => {
397
+ const root: Error = new Error("level-0");
398
+ const levelOne: Error = new Error("level-1");
399
+ const levelTwo: Error = new Error("level-2");
400
+ const levelThree: Error = new Error("level-3");
401
+ const levelFour: Error = new Error("level-4");
402
+ Object.defineProperty(root, "cause", { value: levelOne });
403
+ Object.defineProperty(levelOne, "cause", { value: levelTwo });
404
+ Object.defineProperty(levelTwo, "cause", { value: levelThree });
405
+ Object.defineProperty(levelThree, "cause", { value: levelFour });
406
+
407
+ const serialized: SerializedSupportError = serializeSupportError(root);
408
+
409
+ expect(serialized.cause?.cause?.cause?.message).toBe("level-3");
410
+ expect(serialized.cause?.cause?.cause?.cause).toBeNull();
411
+ expect(serialized.cause?.cause?.cause?.causeTruncated).toBe(true);
412
+ });
413
+ });
414
+
415
+ describe("React component stack helpers", () => {
416
+ test("extracts the first component from modern and legacy stack formats", () => {
417
+ expect(getComponentFromStack("\n at TraceChart (chart.tsx:1:2)")).toBe(
418
+ "TraceChart",
419
+ );
420
+ expect(getComponentFromStack("\n in LegacyChart (created by App)")).toBe(
421
+ "LegacyChart",
422
+ );
423
+ });
424
+
425
+ test("returns null when no component stack is available", () => {
426
+ expect(getComponentFromStack(null)).toBeNull();
427
+ expect(getComponentFromStack("")).toBeNull();
428
+ });
429
+
430
+ test("scrubs every call even though the URL matcher is global", () => {
431
+ const first: string = scrubUrlsInSupportText(
432
+ "at a (https://example.com/a?token=first)",
433
+ );
434
+ const second: string = scrubUrlsInSupportText(
435
+ "at b (https://example.com/b?token=second)",
436
+ );
437
+ const uppercaseScheme: string = scrubUrlsInSupportText(
438
+ "at c (HTTPS://example.com/oauth?code=uppercase-secret)",
439
+ );
440
+
441
+ expect(first).not.toContain("first");
442
+ expect(second).not.toContain("second");
443
+ expect(uppercaseScheme).not.toContain("uppercase-secret");
444
+ });
445
+
446
+ test("redacts private keys, provider tokens, JWTs, and payment cards", () => {
447
+ const sensitiveText: string = [
448
+ "-----BEGIN PRIVATE KEY-----\nprivate-material\n-----END PRIVATE KEY-----",
449
+ "ghp_abcdefghijklmnopqrstuvwxyzABCDEFGHIJ123456",
450
+ "eyJabcdefghijk.eyJabcdefghijk.signature123",
451
+ "4111 1111 1111 1111",
452
+ ].join("\n");
453
+ const redacted: string = redactSensitiveSupportText(sensitiveText);
454
+
455
+ expect(redacted).not.toContain("private-material");
456
+ expect(redacted).not.toContain("ghp_");
457
+ expect(redacted).not.toContain("eyJabcdefghijk");
458
+ expect(redacted).not.toContain("4111 1111 1111 1111");
459
+ });
460
+ });
461
+
462
+ describe("collectErrorSupportBundleRuntimeDetails", () => {
463
+ const originalUrl: string = window.location.href;
464
+ const originalTitle: string = document.title;
465
+ const originalEnvironmentSecret: string | undefined =
466
+ process.env["SUPPORT_BUNDLE_SECRET"];
467
+
468
+ afterEach(() => {
469
+ window.history.replaceState({}, "", originalUrl);
470
+ document.title = originalTitle;
471
+ window.localStorage.clear();
472
+ window.sessionStorage.clear();
473
+ document.cookie = "supportBundleCookie=; Max-Age=0; path=/";
474
+ if (originalEnvironmentSecret === undefined) {
475
+ delete process.env["SUPPORT_BUNDLE_SECRET"];
476
+ } else {
477
+ process.env["SUPPORT_BUNDLE_SECRET"] = originalEnvironmentSecret;
478
+ }
479
+ });
480
+
481
+ test("collects browser context while scrubbing identifiers, query, and fragment", () => {
482
+ window.history.replaceState(
483
+ {},
484
+ "",
485
+ "/dashboard/48aa764b-b3a4-4995-b5f8-0d0c35fc1226/traces?token=page-secret#private-fragment",
486
+ );
487
+ document.title = "Traces | OneUptime";
488
+
489
+ const runtimeDetails: ErrorSupportBundleRuntimeDetails =
490
+ collectErrorSupportBundleRuntimeDetails();
491
+
492
+ expect(runtimeDetails.page.url).toContain("/dashboard/[redacted]/traces");
493
+ expect(runtimeDetails.page.url).not.toContain("page-secret");
494
+ expect(runtimeDetails.page.url).not.toContain("private-fragment");
495
+ expect(runtimeDetails.page.pathname).toBe("/dashboard/[redacted]/traces");
496
+ expect(runtimeDetails.page.hadQueryString).toBe(true);
497
+ expect(runtimeDetails.page.hadFragment).toBe(true);
498
+ expect(runtimeDetails.page.documentTitle).toBe("Traces | OneUptime");
499
+ expect(runtimeDetails.browser.userAgent.length).toBeGreaterThan(0);
500
+ expect(runtimeDetails.browser.timeZone.length).toBeGreaterThan(0);
501
+ expect(runtimeDetails.application.reactVersion.length).toBeGreaterThan(0);
502
+ });
503
+
504
+ test("never includes cookie, storage, or arbitrary environment contents", () => {
505
+ document.cookie = "supportBundleCookie=cookie-secret; path=/";
506
+ window.localStorage.setItem("support-secret", "local-storage-secret");
507
+ window.sessionStorage.setItem("support-secret", "session-storage-secret");
508
+
509
+ process.env["SUPPORT_BUNDLE_SECRET"] = "environment-secret";
510
+
511
+ const bundle: ErrorSupportBundle = createErrorSupportBundle({
512
+ error: new Error("Boom"),
513
+ runtimeDetails: collectErrorSupportBundleRuntimeDetails(),
514
+ });
515
+ const serialized: string = JSON.stringify(bundle);
516
+
517
+ expect(serialized).not.toContain("cookie-secret");
518
+ expect(serialized).not.toContain("local-storage-secret");
519
+ expect(serialized).not.toContain("session-storage-secret");
520
+ expect(serialized).not.toContain("environment-secret");
521
+ expect(serialized).not.toContain("SUPPORT_BUNDLE_SECRET");
522
+ });
523
+
524
+ test("survives an unavailable service worker API", () => {
525
+ const originalDescriptor: PropertyDescriptor | undefined =
526
+ Object.getOwnPropertyDescriptor(navigator, "serviceWorker");
527
+
528
+ Object.defineProperty(navigator, "serviceWorker", {
529
+ configurable: true,
530
+ get: () => {
531
+ throw new Error("SecurityError");
532
+ },
533
+ });
534
+
535
+ try {
536
+ const runtimeDetails: ErrorSupportBundleRuntimeDetails =
537
+ collectErrorSupportBundleRuntimeDetails();
538
+
539
+ expect(runtimeDetails.serviceWorker.isControlled).toBe(false);
540
+ expect(runtimeDetails.serviceWorker.scriptUrl).toBeNull();
541
+ } finally {
542
+ if (originalDescriptor) {
543
+ Object.defineProperty(navigator, "serviceWorker", originalDescriptor);
544
+ } else {
545
+ delete (navigator as { serviceWorker?: ServiceWorkerContainer })
546
+ .serviceWorker;
547
+ }
548
+ }
549
+ });
550
+ });
551
+
552
+ describe("error support bundle download", () => {
553
+ beforeEach(() => {
554
+ downloadFileMock.mockClear();
555
+ });
556
+
557
+ test("uses a deterministic filesystem-safe filename", () => {
558
+ expect(
559
+ getErrorSupportBundleFilename(new Date("2026-08-07T12:34:56.789Z")),
560
+ ).toBe("oneuptime-error-support-bundle-2026-08-07T12-34-56.json");
561
+ });
562
+
563
+ test("downloads pretty-printed JSON with the correct MIME type", () => {
564
+ const bundle: ErrorSupportBundle = downloadErrorSupportBundle({
565
+ error: new Error("Download me"),
566
+ componentStack: "\n at BrokenPage (BrokenPage.tsx:4:2)",
567
+ generatedAt: new Date("2026-08-07T12:34:56.789Z"),
568
+ runtimeDetails: getRuntimeDetails(),
569
+ });
570
+
571
+ expect(downloadFileMock).toHaveBeenCalledTimes(1);
572
+
573
+ const download: Parameters<typeof downloadFile>[0] =
574
+ downloadFileMock.mock.calls[0]![0];
575
+ expect(download.filename).toBe(
576
+ "oneuptime-error-support-bundle-2026-08-07T12-34-56.json",
577
+ );
578
+ expect(download.mimeType).toBe("application/json;charset=utf-8;");
579
+ expect(download.content).toContain('\n "schemaVersion": 1');
580
+ expect(JSON.parse(download.content as string)).toEqual(bundle);
581
+ });
582
+ });
@@ -185,6 +185,21 @@ describe("ProjectUtil", () => {
185
185
 
186
186
  expect(ProjectUtil.getProjectIdFromUrl()).toBeNull();
187
187
  });
188
+
189
+ test.each([
190
+ ["the overview", `/status-page/${PROJECT_Y_ID}`],
191
+ [
192
+ "a nested subscribe page",
193
+ `/status-page/${PROJECT_Y_ID}/subscribe/email`,
194
+ ],
195
+ ])(
196
+ "does not mistake a status-page id for a project id on %s",
197
+ (_description: string, url: string) => {
198
+ setUrl(url);
199
+
200
+ expect(ProjectUtil.getProjectIdFromUrl()).toBeNull();
201
+ },
202
+ );
188
203
  });
189
204
 
190
205
  describe("getCurrentProjectId precedence", () => {
@@ -279,6 +294,22 @@ describe("ProjectUtil", () => {
279
294
 
280
295
  expect(ProjectUtil.getCurrentProjectId()?.toString()).toBe(PROJECT_Y_ID);
281
296
  });
297
+
298
+ test("a status-page preview does not override this tab's dashboard project", () => {
299
+ window.sessionStorage.setItem(
300
+ CURRENT_PROJECT_ID_STORAGE_KEY,
301
+ PROJECT_X_ID,
302
+ );
303
+ setUrl(`/status-page/${PROJECT_Y_ID}/subscribe/email`);
304
+
305
+ expect(ProjectUtil.getCurrentProjectId()?.toString()).toBe(PROJECT_X_ID);
306
+ });
307
+
308
+ test("a status-page preview is not project-scoped when no project is stored", () => {
309
+ setUrl(`/status-page/${PROJECT_Y_ID}/subscribe/email`);
310
+
311
+ expect(ProjectUtil.getCurrentProjectId()).toBeNull();
312
+ });
282
313
  });
283
314
 
284
315
  describe("last accessed project id", () => {