@oneuptime/common 14.0.7 → 14.0.9

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 (1064) hide show
  1. package/Models/DatabaseModels/Incident.ts +267 -1
  2. package/Models/DatabaseModels/IncidentCustomField.ts +202 -0
  3. package/Models/DatabaseModels/IncidentEpisode.ts +30 -0
  4. package/Models/DatabaseModels/IncidentTemplate.ts +126 -1
  5. package/Models/DatabaseModels/Index.ts +2 -0
  6. package/Models/DatabaseModels/KubernetesAiAgent.ts +364 -0
  7. package/Models/DatabaseModels/KubernetesCluster.ts +3 -3
  8. package/Models/DatabaseModels/Project.ts +55 -5
  9. package/Models/DatabaseModels/ProxmoxResource.ts +49 -1
  10. package/Models/DatabaseModels/RunnerJob.ts +75 -0
  11. package/Models/DatabaseModels/StatusPage.ts +55 -0
  12. package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
  13. package/Models/DatabaseModels/TeamComplianceSetting.ts +143 -2
  14. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +17 -0
  15. package/Server/API/AIChatAPI.ts +6 -3
  16. package/Server/API/AIInvestigationAPI.ts +17 -10
  17. package/Server/API/AutoRemediationAPI.ts +207 -25
  18. package/Server/API/IncidentAPI.ts +162 -0
  19. package/Server/API/KubernetesClusterAiAccessAPI.ts +623 -21
  20. package/Server/API/MicrosoftTeamsAPI.ts +93 -14
  21. package/Server/API/ProxmoxResourceAPI.ts +244 -14
  22. package/Server/API/StatusPageAPI.ts +487 -171
  23. package/Server/API/StatusPageSubscriberAPI.ts +63 -15
  24. package/Server/Infrastructure/GlobalCache.ts +32 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.ts +99 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.ts +137 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.ts +42 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
  36. package/Server/Infrastructure/Semaphore.ts +10 -0
  37. package/Server/Middleware/IdentityRateLimit.ts +108 -3
  38. package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
  39. package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
  40. package/Server/Middleware/TelemetryIngest.ts +41 -18
  41. package/Server/Services/AIService.ts +70 -1
  42. package/Server/Services/AlertService.ts +352 -11
  43. package/Server/Services/AlertSeverityService.ts +65 -15
  44. package/Server/Services/AutoRemediationRuleService.ts +1 -1
  45. package/Server/Services/DatabaseService.ts +93 -10
  46. package/Server/Services/IncidentCustomFieldService.ts +276 -1
  47. package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
  48. package/Server/Services/IncidentEpisodeService.ts +15 -0
  49. package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
  50. package/Server/Services/IncidentPublicNoteService.ts +30 -1
  51. package/Server/Services/IncidentService.ts +1788 -142
  52. package/Server/Services/IncidentSeverityService.ts +66 -15
  53. package/Server/Services/IncidentStateTimelineService.ts +13 -0
  54. package/Server/Services/IncidentTemplateService.ts +109 -0
  55. package/Server/Services/KubernetesAiAgentJobService.ts +185 -0
  56. package/Server/Services/KubernetesAiAgentService.ts +1634 -0
  57. package/Server/Services/KubernetesClusterAiAccessService.ts +1118 -451
  58. package/Server/Services/KubernetesClusterService.ts +129 -21
  59. package/Server/Services/ProjectService.ts +32 -0
  60. package/Server/Services/ProxmoxResourceService.ts +322 -5
  61. package/Server/Services/RunnerJobService.ts +241 -104
  62. package/Server/Services/RunnerService.ts +1 -1
  63. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
  64. package/Server/Services/ScheduledMaintenanceService.ts +805 -19
  65. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +414 -56
  66. package/Server/Services/SmsService.ts +10 -0
  67. package/Server/Services/StatusPageService.ts +65 -8
  68. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
  69. package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
  70. package/Server/Services/StatusPageSubscriberService.ts +1161 -64
  71. package/Server/Services/TeamComplianceSettingService.ts +1125 -9
  72. package/Server/Types/Markdown.ts +153 -6
  73. package/Server/Types/Workflow/Components/Email.ts +61 -2
  74. package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +67 -9
  75. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +39 -10
  76. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +14 -3
  77. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +37 -15
  78. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +67 -24
  79. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +48 -5
  80. package/Server/Utils/AI/SRE/IncidentPostmortemRunner.ts +40 -8
  81. package/Server/Utils/AI/SRE/InvestigationEligibility.ts +13 -2
  82. package/Server/Utils/AI/SRE/InvestigationGrader.ts +1 -1
  83. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +6 -1
  84. package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
  85. package/Server/Utils/DataSource/EgressGuard.ts +66 -21
  86. package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
  87. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
  88. package/Server/Utils/SSRFProtection.ts +76 -16
  89. package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
  90. package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
  91. package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
  92. package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
  93. package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
  94. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
  95. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
  96. package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
  97. package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
  98. package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
  99. package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
  100. package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
  101. package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
  102. package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
  103. package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
  104. package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
  105. package/Server/Utils/StatusPageResource.ts +51 -20
  106. package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +133 -7
  107. package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +58 -4
  108. package/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.ts +447 -0
  109. package/Server/Utils/Telemetry/ProxmoxNativePush.ts +903 -0
  110. package/Server/Utils/Telemetry/TelemetryEntity.ts +87 -27
  111. package/Server/Utils/VM/VMAPI.ts +1 -0
  112. package/Server/Utils/VM/VMRunner.ts +10 -0
  113. package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
  114. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +684 -47
  115. package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
  116. package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
  117. package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
  118. package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
  119. package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
  120. package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
  121. package/Tests/App/AdminDashboard/RowActionPlacementOverrides.test.tsx +278 -0
  122. package/Tests/App/Dashboard/AIChatChartWidgetZoom.test.tsx +738 -0
  123. package/Tests/App/Dashboard/AIFeaturesSettingsPointers.test.tsx +147 -0
  124. package/Tests/App/Dashboard/AIInsightsKubernetesClusterPage.test.tsx +1523 -0
  125. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +463 -3
  126. package/Tests/App/Dashboard/AffectedResourcesPickerDropdownPlacement.test.tsx +958 -0
  127. package/Tests/App/Dashboard/AffectedResourcesPickerFocusLeave.test.tsx +595 -0
  128. package/Tests/App/Dashboard/AskAiAvailability.test.ts +20 -3
  129. package/Tests/App/Dashboard/AskAiDisabled.test.tsx +8 -3
  130. package/Tests/App/Dashboard/CephRateChartReload.test.tsx +1456 -0
  131. package/Tests/App/Dashboard/CephTimeRangeZoom.test.tsx +1229 -0
  132. package/Tests/App/Dashboard/ChartCardTimeRangeZoom.test.tsx +151 -0
  133. package/Tests/App/Dashboard/ChartCardZoomAffordances.test.tsx +257 -0
  134. package/Tests/App/Dashboard/ChartRefetchFrame.test.tsx +141 -0
  135. package/Tests/App/Dashboard/ChartZoomHarness.tsx +249 -0
  136. package/Tests/App/Dashboard/ChartZoomStandIn.tsx +131 -0
  137. package/Tests/App/Dashboard/CloudServerlessSlowLoads.test.tsx +628 -0
  138. package/Tests/App/Dashboard/CloudServerlessTimeRangeZoom.test.tsx +607 -0
  139. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +91 -19
  140. package/Tests/App/Dashboard/CompanionMetricsTabZoom.test.tsx +632 -0
  141. package/Tests/App/Dashboard/ContainerChartZoomStandIn.tsx +195 -0
  142. package/Tests/App/Dashboard/ContainerHostOverviewSlowLoads.test.tsx +542 -0
  143. package/Tests/App/Dashboard/ContainerHostOverviewTimeRangeZoom.test.tsx +848 -0
  144. package/Tests/App/Dashboard/ContainerMetricsTimeRangeZoom.test.tsx +561 -0
  145. package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
  146. package/Tests/App/Dashboard/DashboardBoardWideZoomShell.test.tsx +1147 -0
  147. package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +3 -2
  148. package/Tests/App/Dashboard/DashboardHistogramWidgetDragCursor.test.tsx +399 -0
  149. package/Tests/App/Dashboard/DashboardHistogramWidgetZoom.test.tsx +985 -0
  150. package/Tests/App/Dashboard/DashboardHistogramWidgetZoomHint.test.tsx +803 -0
  151. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +1 -0
  152. package/Tests/App/Dashboard/DashboardSettingsPreviewZoom.test.tsx +679 -0
  153. package/Tests/App/Dashboard/DashboardSloAndDataSourceChartZoom.test.tsx +881 -0
  154. package/Tests/App/Dashboard/DashboardTraceStatusWidgets.test.tsx +878 -0
  155. package/Tests/App/Dashboard/DatabaseMetricChartModalTimeRangeZoom.test.tsx +442 -0
  156. package/Tests/App/Dashboard/DatabaseOverviewTimeRangeZoom.test.tsx +831 -0
  157. package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +43 -0
  158. package/Tests/App/Dashboard/DockerSwarmInsightsTimeRangeZoom.test.tsx +524 -0
  159. package/Tests/App/Dashboard/DockerSwarmRateChartRefresh.test.tsx +259 -0
  160. package/Tests/App/Dashboard/EdgeDetailPanelHistory.test.tsx +763 -0
  161. package/Tests/App/Dashboard/EdgeDetailPanelTimeRangeZoom.test.tsx +547 -0
  162. package/Tests/App/Dashboard/EdgeHistoryBucketsCases.tsx +565 -0
  163. package/Tests/App/Dashboard/EdgeHistoryBucketsKathmandu.test.tsx +73 -0
  164. package/Tests/App/Dashboard/EdgeHistoryBucketsKolkata.test.tsx +74 -0
  165. package/Tests/App/Dashboard/EdgeHistoryBucketsNewYork.test.tsx +72 -0
  166. package/Tests/App/Dashboard/EdgeHistoryBucketsUtc.test.tsx +72 -0
  167. package/Tests/App/Dashboard/EmbeddedMetricCardRefresh.test.tsx +310 -0
  168. package/Tests/App/Dashboard/EmbeddedMetricCardTimeRangeZoom.test.tsx +536 -0
  169. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +3 -1
  170. package/Tests/App/Dashboard/EscalationRuleRowActions.test.tsx +660 -0
  171. package/Tests/App/Dashboard/EventNotes.test.tsx +778 -2
  172. package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
  173. package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
  174. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +828 -17
  175. package/Tests/App/Dashboard/EventOverviewSnapshotExplorerZoom.test.tsx +1139 -0
  176. package/Tests/App/Dashboard/EventOverviewSnapshotZoomAcrossTabs.test.tsx +1057 -0
  177. package/Tests/App/Dashboard/EventOverviewTelemetrySnapshotZoom.test.tsx +757 -0
  178. package/Tests/App/Dashboard/ExceptionOccurrenceTrendZoom.test.tsx +675 -0
  179. package/Tests/App/Dashboard/ExceptionOccurrencesZoomSurvivesViewSwitch.test.tsx +405 -0
  180. package/Tests/App/Dashboard/ExceptionSignalPages.test.tsx +67 -3
  181. package/Tests/App/Dashboard/ExceptionTablesSpanStatus.test.tsx +515 -0
  182. package/Tests/App/Dashboard/ExplorerOwnZoomRegression.test.tsx +739 -0
  183. package/Tests/App/Dashboard/FlowBandwidthAxisCases.tsx +461 -0
  184. package/Tests/App/Dashboard/FlowBandwidthAxisKathmandu.test.tsx +25 -0
  185. package/Tests/App/Dashboard/FlowBandwidthAxisKolkata.test.tsx +25 -0
  186. package/Tests/App/Dashboard/FlowBandwidthAxisNewYork.test.tsx +25 -0
  187. package/Tests/App/Dashboard/FlowBandwidthAxisUtc.test.tsx +24 -0
  188. package/Tests/App/Dashboard/FlowTopTalkersZoomRefetch.test.tsx +722 -0
  189. package/Tests/App/Dashboard/FlowViewportGuard.test.tsx +2526 -0
  190. package/Tests/App/Dashboard/HostPagesSlowLoads.test.tsx +872 -0
  191. package/Tests/App/Dashboard/HostPagesTimeRangeZoom.test.tsx +1208 -0
  192. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
  193. package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
  194. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
  195. package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
  196. package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
  197. package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
  198. package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
  199. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
  200. package/Tests/App/Dashboard/IncidentRootCauseTimeRangeZoom.test.tsx +358 -0
  201. package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
  202. package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
  203. package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
  204. package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
  205. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +100 -9
  206. package/Tests/App/Dashboard/InfrastructureMetricsTabTimeRangeZoom.test.tsx +485 -0
  207. package/Tests/App/Dashboard/InvestigationDrawerCompanionZoom.test.tsx +655 -0
  208. package/Tests/App/Dashboard/InvestigationDrawerZoom.test.tsx +830 -0
  209. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +338 -2
  210. package/Tests/App/Dashboard/InvoicesPayInvoice.test.tsx +454 -16
  211. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +799 -819
  212. package/Tests/App/Dashboard/KubernetesClusterAiAgentOverviewCard.test.tsx +367 -0
  213. package/Tests/App/Dashboard/KubernetesClusterAiAgentStatus.test.ts +1202 -0
  214. package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +106 -0
  215. package/Tests/App/Dashboard/KubernetesClusterAiNavigation.test.tsx +354 -0
  216. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +1884 -2054
  217. package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +478 -179
  218. package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +50 -0
  219. package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +2 -1
  220. package/Tests/App/Dashboard/KubernetesClusterOverviewZoom.test.tsx +1217 -0
  221. package/Tests/App/Dashboard/KubernetesClusterPagesZoom.test.tsx +731 -0
  222. package/Tests/App/Dashboard/KubernetesCostsLoadRecovery.test.tsx +869 -0
  223. package/Tests/App/Dashboard/KubernetesCostsZoom.test.tsx +1214 -0
  224. package/Tests/App/Dashboard/KubernetesCostsZoomExactHours.test.tsx +692 -0
  225. package/Tests/App/Dashboard/KubernetesNetworkThroughputReload.test.tsx +902 -0
  226. package/Tests/App/Dashboard/KubernetesNetworkZoomBucketEdges.test.tsx +571 -0
  227. package/Tests/App/Dashboard/KubernetesOverviewZoomBucketEdges.test.tsx +697 -0
  228. package/Tests/App/Dashboard/KubernetesResourceMetricsTabZoom.test.tsx +633 -0
  229. package/Tests/App/Dashboard/LogsExplorerTimeRangeZoom.test.tsx +470 -0
  230. package/Tests/App/Dashboard/LogsInsightsTimeRangeZoom.test.tsx +948 -0
  231. package/Tests/App/Dashboard/LogsViewerPinnedWindowZoom.test.tsx +486 -0
  232. package/Tests/App/Dashboard/MetricChartsBucketInspectorDoubleClick.test.tsx +1001 -0
  233. package/Tests/App/Dashboard/MetricExplorerInvestigationAutoRefresh.test.tsx +514 -0
  234. package/Tests/App/Dashboard/MetricExplorerSavedViewZoomRoundTrip.test.tsx +581 -0
  235. package/Tests/App/Dashboard/MetricExplorerTimeRangeZoom.test.tsx +1162 -0
  236. package/Tests/App/Dashboard/MetricMonitorPreviewZoomLabel.test.ts +72 -0
  237. package/Tests/App/Dashboard/MetricRowSparklineTimeRangeZoom.test.tsx +204 -0
  238. package/Tests/App/Dashboard/MetricViewFirstResultLands.test.tsx +408 -0
  239. package/Tests/App/Dashboard/MetricViewOwnZoomResetPlacement.test.tsx +952 -0
  240. package/Tests/App/Dashboard/MetricViewTimeRange.test.ts +139 -0
  241. package/Tests/App/Dashboard/MetricViewTimeRangeZoom.test.tsx +556 -0
  242. package/Tests/App/Dashboard/MonitorMetricsChartWrappersZoom.test.tsx +552 -0
  243. package/Tests/App/Dashboard/MonitorMetricsTabsTimeRangeZoom.test.tsx +740 -0
  244. package/Tests/App/Dashboard/MonitorOverviewChartsTimeRangeZoom.test.tsx +735 -0
  245. package/Tests/App/Dashboard/MonitorStepPreviewsTimeRangeZoom.test.tsx +835 -0
  246. package/Tests/App/Dashboard/NetworkDeviceTimeRangeZoom.test.tsx +1115 -0
  247. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +186 -17
  248. package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +155 -46
  249. package/Tests/App/Dashboard/PasskeySettings.test.tsx +87 -2
  250. package/Tests/App/Dashboard/ProjectAISettingsPages.test.tsx +884 -0
  251. package/Tests/App/Dashboard/ProxmoxNodeRemove.test.tsx +621 -0
  252. package/Tests/App/Dashboard/ProxmoxOverviewSlowLoads.test.tsx +584 -0
  253. package/Tests/App/Dashboard/ProxmoxPagesTimeRangeZoom.test.tsx +823 -0
  254. package/Tests/App/Dashboard/ProxmoxRateChartReload.test.tsx +1253 -0
  255. package/Tests/App/Dashboard/PublicDashboardBoardWideZoom.test.tsx +605 -0
  256. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
  257. package/Tests/App/Dashboard/RealRowsLineChart.tsx +250 -0
  258. package/Tests/App/Dashboard/RechartsHostsPlotCursor.test.tsx +513 -0
  259. package/Tests/App/Dashboard/RowActionPlacementOverrides.test.tsx +865 -0
  260. package/Tests/App/Dashboard/RumOverviewTimeRangeZoom.test.tsx +877 -0
  261. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +20 -4
  262. package/Tests/App/Dashboard/RunnerSupersededByAiAgentNote.test.tsx +296 -0
  263. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +146 -36
  264. package/Tests/App/Dashboard/ServiceDatabaseSlowLoads.test.tsx +1166 -0
  265. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +1243 -104
  266. package/Tests/App/Dashboard/ServiceOverviewTimeRangeZoom.test.tsx +792 -0
  267. package/Tests/App/Dashboard/SloBudgetBurnDownZoom.test.tsx +771 -0
  268. package/Tests/App/Dashboard/SloBudgetBurnDownZoomAffordances.test.tsx +380 -0
  269. package/Tests/App/Dashboard/SloEventMetricsBarChartZoom.test.tsx +369 -0
  270. package/Tests/App/Dashboard/SloHistoryChartsTimeRangeZoom.test.tsx +694 -0
  271. package/Tests/App/Dashboard/SloHistoryChartsZoomAffordances.test.tsx +497 -0
  272. package/Tests/App/Dashboard/SloMetricsTimeRangeZoom.test.tsx +541 -0
  273. package/Tests/App/Dashboard/SlowLoadHarness.ts +123 -0
  274. package/Tests/App/Dashboard/SnapshotExplorerPrimaryZoom.test.tsx +1194 -0
  275. package/Tests/App/Dashboard/SnapshotViewerPinnedWindow.test.tsx +620 -0
  276. package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
  277. package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
  278. package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
  279. package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
  280. package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
  281. package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
  282. package/Tests/App/Dashboard/TelemetrySnapshotPanelTimeRangeZoom.test.tsx +765 -0
  283. package/Tests/App/Dashboard/TelemetrySnapshotZoom.test.tsx +516 -0
  284. package/Tests/App/Dashboard/TelemetrySnapshotZoomAcrossTabs.test.tsx +827 -0
  285. package/Tests/App/Dashboard/TimeRangeZoomPageHarness.tsx +463 -0
  286. package/Tests/App/Dashboard/TraceChartEditorStatusSplit.test.tsx +543 -0
  287. package/Tests/App/Dashboard/TraceStatusPresentation.test.tsx +967 -0
  288. package/Tests/App/Dashboard/TraceTimelineMinimapZoom.test.tsx +315 -0
  289. package/Tests/App/Dashboard/TracesAnalyticsStatusSplit.test.tsx +778 -0
  290. package/Tests/App/Dashboard/TracesAnalyticsViewZoom.test.tsx +349 -0
  291. package/Tests/App/Dashboard/TracesExplorerTimeRangeZoom.test.tsx +551 -0
  292. package/Tests/App/Dashboard/TracesStatusChartAndFacet.test.tsx +687 -0
  293. package/Tests/App/Dashboard/TracesViewerStaleResponses.test.tsx +458 -0
  294. package/Tests/App/Dashboard/UptimeStripsExcludedFromZoom.test.tsx +406 -0
  295. package/Tests/App/Dashboard/VMwareOverviewSlowLoads.test.tsx +535 -0
  296. package/Tests/App/Dashboard/VMwarePagesTimeRangeZoom.test.tsx +606 -0
  297. package/Tests/App/Dashboard/ValueWidgetSparklineStaleHover.test.tsx +1292 -0
  298. package/Tests/App/Dashboard/ValueWidgetSparklineZoom.test.tsx +765 -0
  299. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
  300. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +98 -0
  301. package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
  302. package/Tests/Models/DatabaseModels/KubernetesAiAgentModel.test.ts +295 -0
  303. package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +347 -0
  304. package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
  305. package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
  306. package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
  307. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +58 -0
  308. package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +1 -1
  309. package/Tests/Server/API/AIInvestigationAPI.test.ts +123 -45
  310. package/Tests/Server/API/AutoRemediationApproveClusterRound.test.ts +1329 -0
  311. package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +25 -2
  312. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
  313. package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
  314. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -0
  315. package/Tests/Server/API/KubernetesClusterAiAccessAPIAgent.test.ts +903 -0
  316. package/Tests/Server/API/MicrosoftTeamsChatsRefreshRoute.test.ts +667 -0
  317. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +294 -6
  318. package/Tests/Server/API/ProxmoxResourceAPIRemoveNode.test.ts +1932 -0
  319. package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
  320. package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
  321. package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
  322. package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
  323. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
  324. package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
  325. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
  326. package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
  327. package/Tests/Server/Infrastructure/GlobalCache.test.ts +195 -0
  328. package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
  329. package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
  330. package/Tests/Server/Infrastructure/Postgres/AddKubernetesAiAgentAndAiDefaultsMigration.test.ts +623 -0
  331. package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +87 -10
  332. package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
  333. package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleScopeMigration.test.ts +622 -0
  334. package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
  335. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
  336. package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
  337. package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
  338. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +61 -4
  339. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +98 -2
  340. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +105 -2
  341. package/Tests/Server/Services/AIServiceBalanceBlocker.test.ts +282 -0
  342. package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
  343. package/Tests/Server/Services/AlertMonitorClearWritesNull.test.ts +409 -0
  344. package/Tests/Server/Services/AlertMonitorEditFeed.test.ts +474 -0
  345. package/Tests/Server/Services/AlertMonitorEditGuard.test.ts +610 -0
  346. package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +2 -0
  347. package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +2 -1
  348. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
  349. package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
  350. package/Tests/Server/Services/IncidentAffectedMonitorsEdit.test.ts +1360 -0
  351. package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +3 -1
  352. package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
  353. package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
  354. package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
  355. package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
  356. package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
  357. package/Tests/Server/Services/IncidentSeverityDeletePausesComplianceRules.test.ts +488 -0
  358. package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
  359. package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
  360. package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
  361. package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
  362. package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
  363. package/Tests/Server/Services/KubernetesAiAgentJobService.test.ts +329 -0
  364. package/Tests/Server/Services/KubernetesAiAgentServiceHelpers.test.ts +618 -0
  365. package/Tests/Server/Services/KubernetesAiAgentServiceLifecycle.test.ts +1444 -0
  366. package/Tests/Server/Services/KubernetesAiAgentServiceRegister.test.ts +1666 -0
  367. package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +140 -111
  368. package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +267 -105
  369. package/Tests/Server/Services/KubernetesClusterAiAccessLegacySuperseded.test.ts +440 -0
  370. package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +567 -411
  371. package/Tests/Server/Services/KubernetesClusterAiAccessTarget.test.ts +1168 -0
  372. package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +410 -12
  373. package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +55 -0
  374. package/Tests/Server/Services/ProjectServiceNewProjectAiDefaults.test.ts +288 -0
  375. package/Tests/Server/Services/ProxmoxResourcePostgres.test.ts +5633 -0
  376. package/Tests/Server/Services/ProxmoxResourceService.test.ts +6458 -5
  377. package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
  378. package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
  379. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +48 -15
  380. package/Tests/Server/Services/RunnerJobEnqueueKubectlAiAgent.test.ts +620 -0
  381. package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +170 -3
  382. package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +72 -0
  383. package/Tests/Server/Services/RunnerServiceAgentName.test.ts +6 -4
  384. package/Tests/Server/Services/ScheduledMaintenanceAttachmentEdit.test.ts +2113 -0
  385. package/Tests/Server/Services/ScheduledMaintenanceMonitorRelease.test.ts +972 -0
  386. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
  387. package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
  388. package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
  389. package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
  390. package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
  391. package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
  392. package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
  393. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
  394. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
  395. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
  396. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
  397. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
  398. package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
  399. package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
  400. package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
  401. package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
  402. package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +2237 -0
  403. package/Tests/Server/Services/TeamComplianceSettingService.test.ts +3988 -138
  404. package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
  405. package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
  406. package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
  407. package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +107 -1
  408. package/Tests/Server/Utils/AI/IncidentPostmortemRunner.test.ts +351 -0
  409. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +2 -0
  410. package/Tests/Server/Utils/AI/InvestigationEligibility.test.ts +310 -0
  411. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +70 -0
  412. package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +58 -0
  413. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +2 -0
  414. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +2 -0
  415. package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +2 -0
  416. package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +125 -1
  417. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +252 -3
  418. package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +2 -0
  419. package/Tests/Server/Utils/AI/RemediationExecutionRunnerProjectGates.test.ts +240 -0
  420. package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +2 -0
  421. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +2 -0
  422. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +2 -0
  423. package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +2 -0
  424. package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
  425. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
  426. package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
  427. package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
  428. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
  429. package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
  430. package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
  431. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
  432. package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
  433. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
  434. package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
  435. package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
  436. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
  437. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
  438. package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
  439. package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
  440. package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
  441. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
  442. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
  443. package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
  444. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
  445. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
  446. package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
  447. package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
  448. package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
  449. package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
  450. package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
  451. package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
  452. package/Tests/Server/Utils/Telemetry/HostAssetAttributesFromOtlp.test.ts +68 -0
  453. package/Tests/Server/Utils/Telemetry/InventoryMirrorPostgres.test.ts +370 -0
  454. package/Tests/Server/Utils/Telemetry/NetworkDeviceInventoryAttributes.test.ts +522 -0
  455. package/Tests/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.test.ts +155 -0
  456. package/Tests/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.test.ts +8631 -0
  457. package/Tests/Server/Utils/Telemetry/ProxmoxNativePush.test.ts +2852 -0
  458. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +367 -1
  459. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +45 -3
  460. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
  461. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
  462. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +25 -0
  463. package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNames.test.ts +3119 -0
  464. package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNamesPostgres.test.ts +1721 -0
  465. package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
  466. package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
  467. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
  468. package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
  469. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
  470. package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
  471. package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +581 -113
  472. package/Tests/Types/Kubernetes/KubernetesAiAgentAccessContract.test.ts +510 -0
  473. package/Tests/Types/SafeHtml.test.ts +102 -0
  474. package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
  475. package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
  476. package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
  477. package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
  478. package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
  479. package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
  480. package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
  481. package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
  482. package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
  483. package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
  484. package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
  485. package/Tests/Types/Team/ComplianceRule.test.ts +1029 -0
  486. package/Tests/Types/Team/TeamComplianceStatus.test.ts +176 -0
  487. package/Tests/UI/Components/ActionButton/RowActions.test.tsx +641 -0
  488. package/Tests/UI/Components/ActionButton/RowActionsAccessibility.test.tsx +414 -0
  489. package/Tests/UI/Components/ActionButton/SplitActionButtons.test.ts +565 -0
  490. package/Tests/UI/Components/Charts/BarChartDragToSelect.test.tsx +386 -0
  491. package/Tests/UI/Components/Charts/ChartDoubleClickResetWithoutDblclick.test.tsx +1025 -0
  492. package/Tests/UI/Components/Charts/ChartGroupPageZoomHint.test.tsx +196 -0
  493. package/Tests/UI/Components/Charts/ChartPlaceholdersTakeDoubleClick.test.tsx +1861 -0
  494. package/Tests/UI/Components/Charts/ChartPlotClicksWhileResetArmed.test.tsx +382 -0
  495. package/Tests/UI/Components/Charts/ChartRangeSelection.test.tsx +704 -0
  496. package/Tests/UI/Components/Charts/ChartRangeSelectionDoubleClickReset.test.tsx +1481 -0
  497. package/Tests/UI/Components/Charts/ChartRangeSelectionRealRecharts.test.tsx +918 -0
  498. package/Tests/UI/Components/Charts/ChartRowBucketStart.test.ts +350 -0
  499. package/Tests/UI/Components/Charts/DoubleClickReset.test.tsx +996 -0
  500. package/Tests/UI/Components/Charts/HistogramDoubleClickResetRealRecharts.test.tsx +965 -0
  501. package/Tests/UI/Components/Charts/HistogramDriftThenRefetch.test.tsx +277 -0
  502. package/Tests/UI/Components/Charts/HistogramRangeSelectionDataChange.test.tsx +1757 -0
  503. package/Tests/UI/Components/Charts/HistogramRangeSelectionRealRecharts.test.tsx +560 -0
  504. package/Tests/UI/Components/Charts/TimeRangeZoom/ChartPageTimeRangeZoom.test.tsx +513 -0
  505. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.test.tsx +845 -0
  506. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.test.tsx +119 -0
  507. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHintTailwind.test.tsx +274 -0
  508. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.test.ts +433 -0
  509. package/Tests/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.test.tsx +863 -0
  510. package/Tests/UI/Components/Charts/TimeRangeZoom/ZoomDocsPromises.test.tsx +1147 -0
  511. package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
  512. package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
  513. package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
  514. package/Tests/UI/Components/DisabledButtonTooltip.test.tsx +14 -3
  515. package/Tests/UI/Components/EntityDropdownEscape.test.tsx +454 -0
  516. package/Tests/UI/Components/EntityDropdownFocusLeave.test.tsx +420 -0
  517. package/Tests/UI/Components/Forms/FormFieldDropdownDisabled.test.tsx +233 -0
  518. package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
  519. package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
  520. package/Tests/UI/Components/Input.test.tsx +80 -1
  521. package/Tests/UI/Components/LogsAnalyticsViewZoom.test.tsx +947 -0
  522. package/Tests/UI/Components/LogsHistogramDragTooltip.test.tsx +17 -5
  523. package/Tests/UI/Components/LogsViewerAnalyticsZoom.test.tsx +501 -0
  524. package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +1 -1
  525. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +6 -4
  526. package/Tests/UI/Components/ModelTable/BaseModelTablePermissionGating.test.tsx +60 -8
  527. package/Tests/UI/Components/ModelTable/BaseModelTableRowActions.test.tsx +476 -0
  528. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
  529. package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +7 -5
  530. package/Tests/UI/Components/MoreMenuPortal.test.tsx +623 -0
  531. package/Tests/UI/Components/StatusPage/ResourceGridActions.test.tsx +538 -0
  532. package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +14 -4
  533. package/Tests/UI/Components/TableCellWrapping.test.tsx +3 -3
  534. package/Tests/UI/Components/TableRowActions.test.tsx +472 -0
  535. package/Tests/UI/Components/TelemetryHistogramDragTooltip.test.tsx +1 -1
  536. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +1 -1
  537. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerZoomScope.test.tsx +470 -0
  538. package/Tests/UI/Components/TelemetryViewer/UseViewerTimeRangeZoom.test.tsx +571 -0
  539. package/Tests/UI/Components/TelemetryViewer/ViewerDoubleClickResetUnderDataChange.test.tsx +928 -0
  540. package/Tests/UI/Components/TelemetryViewer/ViewerFollowsEnclosingZoom.test.tsx +1569 -0
  541. package/Tests/UI/Components/Toggle.test.tsx +66 -0
  542. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardRefreshNames.test.tsx +1023 -0
  543. package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
  544. package/Tests/UI/Rum/ChunkLoader.test.ts +201 -0
  545. package/Tests/UI/Rum/FidelityNotices.test.ts +54 -0
  546. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +72 -0
  547. package/Tests/UI/Rum/ReplayFrameCapture.test.ts +1009 -9
  548. package/Tests/UI/Rum/ReplayRecordedAssets.test.ts +1069 -0
  549. package/Tests/UI/Rum/ReplayStage.test.tsx +913 -2
  550. package/Tests/UI/Rum/SessionReplayTable.test.tsx +443 -8
  551. package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +439 -9
  552. package/Tests/UI/Rum/UserFlowTablesRowActions.test.tsx +501 -0
  553. package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +47 -19
  554. package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +2 -0
  555. package/Tests/Utils/AiRemediation/KubernetesAiAgentPolicyCopyParity.test.ts +396 -0
  556. package/Tests/Utils/Dashboard/DashboardTimeRangeZoom.test.ts +104 -1
  557. package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
  558. package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
  559. package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
  560. package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
  561. package/Types/AI/AIRunType.ts +9 -4
  562. package/Types/AI/InvestigationNotStartedReason.ts +6 -0
  563. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +14 -16
  564. package/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.ts +28 -0
  565. package/Types/CustomField/CustomFieldOrder.ts +55 -0
  566. package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
  567. package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
  568. package/Types/CustomField/CustomFieldType.ts +14 -0
  569. package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
  570. package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
  571. package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
  572. package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +4 -2
  573. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +263 -32
  574. package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +20 -16
  575. package/Types/Kubernetes/KubernetesClusterAiInsights.ts +81 -0
  576. package/Types/Monitor/ProxmoxAlertTemplates.ts +4 -4
  577. package/Types/SafeHtml.ts +93 -0
  578. package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
  579. package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
  580. package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
  581. package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
  582. package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
  583. package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
  584. package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
  585. package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
  586. package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
  587. package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
  588. package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
  589. package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
  590. package/Types/Team/ComplianceNotificationChannel.ts +22 -0
  591. package/Types/Team/ComplianceRule.ts +434 -0
  592. package/Types/Team/ComplianceRuleType.ts +21 -0
  593. package/Types/Team/TeamComplianceStatus.ts +81 -0
  594. package/Types/Telemetry/TelemetryIngestSurface.ts +28 -0
  595. package/UI/Components/ActionButton/ActionButtonSchema.ts +21 -0
  596. package/UI/Components/ActionButton/RowActions.tsx +238 -0
  597. package/UI/Components/ActionButton/SplitActionButtons.ts +173 -0
  598. package/UI/Components/Charts/Area/AreaChart.tsx +32 -2
  599. package/UI/Components/Charts/Bar/BarChart.tsx +40 -3
  600. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +37 -11
  601. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +80 -243
  602. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +122 -31
  603. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +95 -244
  604. package/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.ts +214 -0
  605. package/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.ts +32 -0
  606. package/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.ts +599 -0
  607. package/UI/Components/Charts/Line/LineChart.tsx +32 -2
  608. package/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.tsx +70 -0
  609. package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.tsx +226 -0
  610. package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.tsx +73 -0
  611. package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.ts +163 -0
  612. package/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.ts +215 -0
  613. package/UI/Components/Charts/Utils/DataPoint.ts +20 -8
  614. package/UI/Components/Charts/Utils/XAxis.ts +75 -0
  615. package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +493 -59
  616. package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
  617. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
  618. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
  619. package/UI/Components/EntityDropdown/EntityDropdown.tsx +107 -11
  620. package/UI/Components/Forms/Fields/FormField.tsx +10 -0
  621. package/UI/Components/Forms/ModelForm.tsx +70 -8
  622. package/UI/Components/Forms/Validation.ts +1 -1
  623. package/UI/Components/Input/Input.tsx +90 -57
  624. package/UI/Components/List/ListRow.tsx +8 -74
  625. package/UI/Components/LogsViewer/LogsViewer.tsx +40 -11
  626. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +22 -6
  627. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +209 -6
  628. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +127 -84
  629. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +3 -0
  630. package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
  631. package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
  632. package/UI/Components/ModelTable/BaseModelTable.tsx +21 -9
  633. package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
  634. package/UI/Components/ModelTable/ModelTable.tsx +6 -7
  635. package/UI/Components/MoreMenu/MoreMenu.tsx +365 -30
  636. package/UI/Components/MoreMenu/MoreMenuItem.tsx +70 -17
  637. package/UI/Components/OrderedStatesList/Item.tsx +7 -72
  638. package/UI/Components/StatusPage/ResourceGrid.tsx +126 -77
  639. package/UI/Components/Table/TableBody.tsx +8 -2
  640. package/UI/Components/Table/TableRow.tsx +20 -140
  641. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +41 -10
  642. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +47 -9
  643. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +25 -6
  644. package/UI/Components/TelemetryViewer/types.ts +2 -0
  645. package/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.ts +448 -0
  646. package/UI/Components/Toggle/Toggle.tsx +26 -0
  647. package/UI/Components/Tooltip/Tooltip.tsx +8 -1
  648. package/UI/Styles/Theme.css +14 -2
  649. package/UI/Utils/SensitiveUrlToken.ts +10 -5
  650. package/Utils/API.ts +247 -2
  651. package/Utils/AiRemediation/CommandPolicy.ts +1 -1
  652. package/Utils/AiRemediation/KubectlPolicy.ts +1 -1
  653. package/Utils/Dashboard/DashboardTimeRangeZoom.ts +46 -2
  654. package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
  655. package/Utils/Markdown/MarkdownEscape.ts +65 -0
  656. package/Utils/ProbeNetworkFailureUtil.ts +673 -0
  657. package/build/dist/Models/DatabaseModels/Incident.js +267 -1
  658. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  659. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
  660. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  661. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
  662. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  663. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
  664. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  665. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  666. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  667. package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js +385 -0
  668. package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js.map +1 -0
  669. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +3 -3
  670. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  671. package/build/dist/Models/DatabaseModels/Project.js +56 -5
  672. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  673. package/build/dist/Models/DatabaseModels/ProxmoxResource.js +51 -1
  674. package/build/dist/Models/DatabaseModels/ProxmoxResource.js.map +1 -1
  675. package/build/dist/Models/DatabaseModels/RunnerJob.js +74 -0
  676. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  677. package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
  678. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  679. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
  680. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  681. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +134 -3
  682. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
  683. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  684. package/build/dist/Server/API/AIChatAPI.js +6 -1
  685. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  686. package/build/dist/Server/API/AIInvestigationAPI.js +17 -10
  687. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  688. package/build/dist/Server/API/AutoRemediationAPI.js +144 -24
  689. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  690. package/build/dist/Server/API/IncidentAPI.js +100 -1
  691. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  692. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +436 -22
  693. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -1
  694. package/build/dist/Server/API/MicrosoftTeamsAPI.js +69 -13
  695. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  696. package/build/dist/Server/API/ProxmoxResourceAPI.js +187 -14
  697. package/build/dist/Server/API/ProxmoxResourceAPI.js.map +1 -1
  698. package/build/dist/Server/API/StatusPageAPI.js +417 -176
  699. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  700. package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
  701. package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
  702. package/build/dist/Server/Infrastructure/GlobalCache.js +27 -0
  703. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  704. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
  705. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
  706. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
  707. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
  708. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
  709. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
  710. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
  711. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
  712. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
  713. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
  714. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
  715. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
  716. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
  717. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
  718. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js +50 -0
  719. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js.map +1 -0
  720. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js +84 -0
  721. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js.map +1 -0
  722. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js +31 -0
  723. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js.map +1 -0
  724. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
  725. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  726. package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
  727. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  728. package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
  729. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
  730. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
  731. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
  732. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
  733. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
  734. package/build/dist/Server/Middleware/TelemetryIngest.js +34 -19
  735. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  736. package/build/dist/Server/Services/AIService.js +59 -1
  737. package/build/dist/Server/Services/AIService.js.map +1 -1
  738. package/build/dist/Server/Services/AlertService.js +248 -13
  739. package/build/dist/Server/Services/AlertService.js.map +1 -1
  740. package/build/dist/Server/Services/AlertSeverityService.js +51 -15
  741. package/build/dist/Server/Services/AlertSeverityService.js.map +1 -1
  742. package/build/dist/Server/Services/AutoRemediationRuleService.js +1 -1
  743. package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
  744. package/build/dist/Server/Services/DatabaseService.js +56 -7
  745. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  746. package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
  747. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  748. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
  749. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  750. package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
  751. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  752. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
  753. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  754. package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
  755. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  756. package/build/dist/Server/Services/IncidentService.js +1251 -72
  757. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  758. package/build/dist/Server/Services/IncidentSeverityService.js +51 -15
  759. package/build/dist/Server/Services/IncidentSeverityService.js.map +1 -1
  760. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  761. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  762. package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
  763. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  764. package/build/dist/Server/Services/KubernetesAiAgentJobService.js +158 -0
  765. package/build/dist/Server/Services/KubernetesAiAgentJobService.js.map +1 -0
  766. package/build/dist/Server/Services/KubernetesAiAgentService.js +1145 -0
  767. package/build/dist/Server/Services/KubernetesAiAgentService.js.map +1 -0
  768. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +842 -371
  769. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -1
  770. package/build/dist/Server/Services/KubernetesClusterService.js +86 -17
  771. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  772. package/build/dist/Server/Services/ProjectService.js +22 -0
  773. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  774. package/build/dist/Server/Services/ProxmoxResourceService.js +258 -3
  775. package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
  776. package/build/dist/Server/Services/RunnerJobService.js +178 -92
  777. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  778. package/build/dist/Server/Services/RunnerService.js +1 -1
  779. package/build/dist/Server/Services/RunnerService.js.map +1 -1
  780. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
  781. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  782. package/build/dist/Server/Services/ScheduledMaintenanceService.js +582 -20
  783. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  784. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +316 -46
  785. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  786. package/build/dist/Server/Services/SmsService.js +2 -22
  787. package/build/dist/Server/Services/SmsService.js.map +1 -1
  788. package/build/dist/Server/Services/StatusPageService.js +47 -9
  789. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  790. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
  791. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  792. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
  793. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
  794. package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
  795. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  796. package/build/dist/Server/Services/TeamComplianceSettingService.js +833 -7
  797. package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
  798. package/build/dist/Server/Types/Markdown.js +110 -6
  799. package/build/dist/Server/Types/Markdown.js.map +1 -1
  800. package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
  801. package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
  802. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +52 -9
  803. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -1
  804. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +13 -9
  805. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
  806. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +7 -3
  807. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
  808. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +29 -15
  809. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  810. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +56 -20
  811. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  812. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +39 -5
  813. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  814. package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js +30 -3
  815. package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js.map +1 -1
  816. package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js +13 -2
  817. package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js.map +1 -1
  818. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +1 -1
  819. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +4 -2
  820. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  821. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
  822. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
  823. package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
  824. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  825. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
  826. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
  827. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
  828. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  829. package/build/dist/Server/Utils/SSRFProtection.js +48 -6
  830. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  831. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
  832. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
  833. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
  834. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
  835. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
  836. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
  837. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
  838. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
  839. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
  840. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
  841. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
  842. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
  843. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
  844. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
  845. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
  846. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
  847. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
  848. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
  849. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
  850. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
  851. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
  852. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
  853. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
  854. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
  855. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
  856. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
  857. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
  858. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
  859. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
  860. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
  861. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
  862. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
  863. package/build/dist/Server/Utils/StatusPageResource.js +39 -7
  864. package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
  865. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +111 -6
  866. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
  867. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +40 -4
  868. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
  869. package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js +296 -0
  870. package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js.map +1 -0
  871. package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js +699 -0
  872. package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js.map +1 -0
  873. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +77 -19
  874. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  875. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  876. package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
  877. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  878. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
  879. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
  880. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +505 -42
  881. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  882. package/build/dist/Types/AI/AIRunType.js +9 -4
  883. package/build/dist/Types/AI/AIRunType.js.map +1 -1
  884. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +10 -16
  885. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  886. package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js +28 -0
  887. package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js.map +1 -0
  888. package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
  889. package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
  890. package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
  891. package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
  892. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
  893. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
  894. package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
  895. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  896. package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
  897. package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
  898. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
  899. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
  900. package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
  901. package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
  902. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +72 -16
  903. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
  904. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +20 -16
  905. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -1
  906. package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js +17 -0
  907. package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js.map +1 -0
  908. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +4 -4
  909. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
  910. package/build/dist/Types/SafeHtml.js +84 -0
  911. package/build/dist/Types/SafeHtml.js.map +1 -0
  912. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
  913. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
  914. package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
  915. package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
  916. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
  917. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
  918. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
  919. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
  920. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
  921. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
  922. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
  923. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
  924. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
  925. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
  926. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
  927. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
  928. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
  929. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
  930. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
  931. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
  932. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
  933. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
  934. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
  935. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
  936. package/build/dist/Types/Team/ComplianceNotificationChannel.js +23 -0
  937. package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -0
  938. package/build/dist/Types/Team/ComplianceRule.js +304 -0
  939. package/build/dist/Types/Team/ComplianceRule.js.map +1 -0
  940. package/build/dist/Types/Team/ComplianceRuleType.js +21 -0
  941. package/build/dist/Types/Team/ComplianceRuleType.js.map +1 -1
  942. package/build/dist/Types/Team/TeamComplianceStatus.js +2 -0
  943. package/build/dist/Types/Team/TeamComplianceStatus.js.map +1 -0
  944. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +25 -0
  945. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  946. package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js +20 -1
  947. package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js.map +1 -1
  948. package/build/dist/UI/Components/ActionButton/RowActions.js +113 -0
  949. package/build/dist/UI/Components/ActionButton/RowActions.js.map +1 -0
  950. package/build/dist/UI/Components/ActionButton/SplitActionButtons.js +71 -0
  951. package/build/dist/UI/Components/ActionButton/SplitActionButtons.js.map +1 -0
  952. package/build/dist/UI/Components/Charts/Area/AreaChart.js +16 -1
  953. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  954. package/build/dist/UI/Components/Charts/Bar/BarChart.js +16 -1
  955. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  956. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +27 -5
  957. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  958. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +61 -194
  959. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  960. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +84 -26
  961. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  962. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +75 -196
  963. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  964. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js +133 -0
  965. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js.map +1 -1
  966. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js +26 -0
  967. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js.map +1 -0
  968. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js +371 -0
  969. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js.map +1 -0
  970. package/build/dist/UI/Components/Charts/Line/LineChart.js +16 -1
  971. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  972. package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js +35 -0
  973. package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js.map +1 -0
  974. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js +107 -0
  975. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js.map +1 -0
  976. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js +41 -0
  977. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js.map +1 -0
  978. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js +117 -0
  979. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js.map +1 -0
  980. package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js +121 -0
  981. package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js.map +1 -0
  982. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -7
  983. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  984. package/build/dist/UI/Components/Charts/Utils/XAxis.js +70 -0
  985. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  986. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +305 -38
  987. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -1
  988. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
  989. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
  990. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
  991. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
  992. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
  993. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  994. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +89 -14
  995. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  996. package/build/dist/UI/Components/Forms/Fields/FormField.js +11 -2
  997. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  998. package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
  999. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  1000. package/build/dist/UI/Components/Forms/Validation.js +1 -1
  1001. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  1002. package/build/dist/UI/Components/Input/Input.js +69 -54
  1003. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  1004. package/build/dist/UI/Components/List/ListRow.js +4 -39
  1005. package/build/dist/UI/Components/List/ListRow.js.map +1 -1
  1006. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +31 -8
  1007. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1008. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +10 -1
  1009. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  1010. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +139 -21
  1011. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  1012. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +30 -8
  1013. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  1014. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
  1015. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  1016. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  1017. package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
  1018. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +12 -2
  1019. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1020. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
  1021. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  1022. package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
  1023. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  1024. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +253 -14
  1025. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  1026. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +43 -13
  1027. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  1028. package/build/dist/UI/Components/OrderedStatesList/Item.js +2 -38
  1029. package/build/dist/UI/Components/OrderedStatesList/Item.js.map +1 -1
  1030. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +53 -15
  1031. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
  1032. package/build/dist/UI/Components/Table/TableBody.js +6 -2
  1033. package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
  1034. package/build/dist/UI/Components/Table/TableRow.js +12 -75
  1035. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  1036. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +32 -7
  1037. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1038. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +27 -9
  1039. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  1040. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +11 -1
  1041. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  1042. package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js +272 -0
  1043. package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js.map +1 -0
  1044. package/build/dist/UI/Components/Toggle/Toggle.js +14 -1
  1045. package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
  1046. package/build/dist/UI/Components/Tooltip/Tooltip.js +1 -1
  1047. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  1048. package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
  1049. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
  1050. package/build/dist/Utils/API.js +177 -1
  1051. package/build/dist/Utils/API.js.map +1 -1
  1052. package/build/dist/Utils/AiRemediation/CommandPolicy.js +1 -1
  1053. package/build/dist/Utils/AiRemediation/CommandPolicy.js.map +1 -1
  1054. package/build/dist/Utils/AiRemediation/KubectlPolicy.js +1 -1
  1055. package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -1
  1056. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js +27 -1
  1057. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js.map +1 -1
  1058. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
  1059. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
  1060. package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
  1061. package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
  1062. package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
  1063. package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
  1064. package/package.json +1 -1
@@ -13,8 +13,10 @@ import { AllowedSubscribersCountInFreePlan, IsBillingEnabled, } from "../Environ
13
13
  import ProjectSMTPConfigService from "../Services/ProjectSmtpConfigService";
14
14
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
15
15
  import QueryHelper from "../Types/Database/QueryHelper";
16
+ import SortOrder from "../../Types/BaseDatabase/SortOrder";
16
17
  import logger from "../Utils/Logger";
17
18
  import DatabaseService from "./DatabaseService";
19
+ import GlobalCache from "../Infrastructure/GlobalCache";
18
20
  import MailService from "./MailService";
19
21
  import ProjectCallSMSConfigService from "./ProjectCallSMSConfigService";
20
22
  import ProjectService from "./ProjectService";
@@ -36,12 +38,109 @@ import MicrosoftTeamsUtil from "../Utils/Workspace/MicrosoftTeams/MicrosoftTeams
36
38
  import StatusPageSubscriberWebhookUtil from "../Utils/StatusPageSubscriberWebhook";
37
39
  import SSRFProtection from "../Utils/SSRFProtection";
38
40
  import StatusPageSubscriberNotificationTemplateService, { Service as StatusPageSubscriberNotificationTemplateServiceClass, } from "./StatusPageSubscriberNotificationTemplateService";
41
+ import TeamMemberService from "./TeamMemberService";
42
+ import UserService from "./UserService";
43
+ import OneUptimeDate from "../../Types/Date";
44
+ import ModelEventType from "../../Types/Realtime/ModelEventType";
45
+ import StatusPageSubscriberUnsubscribe, { StatusPageSubscriberUnsubscribeState, } from "../../Types/StatusPage/StatusPageSubscriberUnsubscribe";
46
+ import StatusPageSubscriberUnsubscribeToken from "../Utils/StatusPage/StatusPageSubscriberUnsubscribeToken";
47
+ import StatusPageSubscriberUnsubscribeNotice, { StatusPageSubscriberUnsubscribeSource, } from "../Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice";
48
+ const returnedRows = (result) => {
49
+ if (!Array.isArray(result)) {
50
+ return [];
51
+ }
52
+ if (result.length === 2 &&
53
+ Array.isArray(result[0]) &&
54
+ typeof result[1] === "number") {
55
+ return result[0];
56
+ }
57
+ return result.filter((row) => {
58
+ return Boolean(row) && typeof row === "object" && !Array.isArray(row);
59
+ });
60
+ };
61
+ const affectedRowCount = (result) => {
62
+ if (Array.isArray(result) &&
63
+ result.length === 2 &&
64
+ typeof result[1] === "number") {
65
+ return result[1];
66
+ }
67
+ return 0;
68
+ };
69
+ /*
70
+ * The subscriber rows being created for a visitor who signed up on the status
71
+ * page itself (see createFromStatusPageSignUp). Every other create - a
72
+ * teammate on the dashboard, an API key, a workflow - is the team adding a
73
+ * subscriber, and onBeforeCreate marks it so (Is Added By Team).
74
+ *
75
+ * The very model instances, held only for the length of the create: nothing
76
+ * a request body carries can put a row in here, so no client can pass its
77
+ * subscriber off as a sign-up and keep the page's owners from hearing when
78
+ * it unsubscribes.
79
+ */
80
+ const statusPageSignUps = new WeakSet();
81
+ // How many subscribers the backfill and the token top-up handle per statement.
82
+ const UNSUBSCRIBE_COLUMNS_BATCH_SIZE = 1000;
39
83
  export class Service extends DatabaseService {
40
84
  constructor() {
41
85
  super(Model);
42
86
  }
87
+ /*
88
+ * A create hands its caller the row it saved, and every caller passes it
89
+ * on whole: BaseAPI serializes it into the response of POST
90
+ * /status-page-subscriber without a column read check (a teammate's Add
91
+ * Subscriber and Add in Bulk, any API key), and a workflow's Create Status
92
+ * Page Subscriber step returns it, to be kept in the workflow's logs.
93
+ *
94
+ * So the two secrets onBeforeCreate minted are taken off it first: the
95
+ * unsubscribe token, which lets whoever holds it cancel the subscription
96
+ * without signing in - and makes the team's notice say the subscriber did -
97
+ * and the six-digit confirmation code. Nobody can read either column
98
+ * (read: []). They leave the server only inside the messages to the
99
+ * subscription's own contact, which onCreateSuccess has sent by now; the
100
+ * confirmation email reads its code back from the database.
101
+ */
102
+ async create(createBy) {
103
+ const created = await super.create(createBy);
104
+ /*
105
+ * Cleared rather than deleted, as BaseAPI.createItem clears a model's
106
+ * `_id`: an unset column holds undefined, which serializes as nothing.
107
+ */
108
+ const row = created;
109
+ row["unsubscribeToken"] = undefined;
110
+ row["subscriptionConfirmationToken"] = undefined;
111
+ return created;
112
+ }
113
+ /*
114
+ * Create the subscriber a visitor signed up for on the status page itself
115
+ * (StatusPageAPI's subscribe endpoint). The one create that is not the team
116
+ * adding a subscriber: it is created as root, like the rest of that
117
+ * endpoint, and Is Added By Team is left off.
118
+ */
119
+ async createFromStatusPageSignUp(data) {
120
+ statusPageSignUps.add(data);
121
+ try {
122
+ return await this.create({
123
+ data: data,
124
+ props: {
125
+ isRoot: true,
126
+ },
127
+ });
128
+ }
129
+ finally {
130
+ statusPageSignUps.delete(data);
131
+ }
132
+ }
133
+ /*
134
+ * Whether the team added this subscriber, rather than it signing up on the
135
+ * status page. Is Added By Team says so for every subscriber created since
136
+ * it existed; Created By is read as well for the ones created before, until
137
+ * the backfill has marked them (every create with a creator is the team's).
138
+ */
139
+ isAddedByTeam(subscriber) {
140
+ return (subscriber.isAddedByTeam === true || Boolean(subscriber.createdByUserId));
141
+ }
43
142
  async onBeforeCreate(data) {
44
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37;
143
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35;
45
144
  logger.debug("onBeforeCreate called with data:", {
46
145
  projectId: (_a = data.data.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
47
146
  statusPageId: (_b = data.data.statusPageId) === null || _b === void 0 ? void 0 : _b.toString(),
@@ -282,26 +381,434 @@ export class Service extends DatabaseService {
282
381
  await SSRFProtection.validateWebhookTargetIsSafe(data.data.subscriberWebhook);
283
382
  }
284
383
  data.data.subscriptionConfirmationToken = NumberUtil.getRandomNumber(100000, 999999).toString();
384
+ /*
385
+ * The secret in this subscriber's unsubscribe link. Always minted here,
386
+ * whatever the request carried: the column is computed, so the create
387
+ * column check lets a client send one, and a token the client chose would
388
+ * be one somebody else could know. A re-subscribe deletes the old row
389
+ * above and gets a new token, so links to the old subscription stop
390
+ * working.
391
+ */
392
+ data.data.unsubscribeToken =
393
+ StatusPageSubscriberUnsubscribeToken.generate();
394
+ /*
395
+ * Never taken from a client either: whether the team added this
396
+ * subscriber. Only a sign-up on the status page is not the team's, and
397
+ * only createFromStatusPageSignUp creates one. A teammate's create carries
398
+ * a creator (Created By) but an API key's or a workflow's does not, so
399
+ * this is the column that says it for all of them.
400
+ */
401
+ data.data.isAddedByTeam = !statusPageSignUps.has(data.data);
402
+ /*
403
+ * Likewise never taken from a client. A subscriber is only ever created
404
+ * unsubscribed through the API, and then it was cancelled now.
405
+ */
406
+ if (data.data.isUnsubscribed) {
407
+ data.data.unsubscribedAt = OneUptimeDate.getCurrentDate();
408
+ }
409
+ else {
410
+ delete data.data.unsubscribedAt;
411
+ }
285
412
  logger.debug(`Subscription Confirmation Token: ${data.data.subscriptionConfirmationToken}`, {
286
413
  projectId: (_32 = data.data.projectId) === null || _32 === void 0 ? void 0 : _32.toString(),
287
414
  statusPageId: (_33 = data.data.statusPageId) === null || _33 === void 0 ? void 0 : _33.toString(),
288
415
  });
289
- logger.debug("onBeforeCreate processed data:", {
416
+ // Not the data itself: it now carries the unsubscribe token.
417
+ logger.debug("onBeforeCreate processed data.", {
290
418
  projectId: (_34 = data.data.projectId) === null || _34 === void 0 ? void 0 : _34.toString(),
291
419
  statusPageId: (_35 = data.data.statusPageId) === null || _35 === void 0 ? void 0 : _35.toString(),
292
420
  });
293
- logger.debug(data, {
294
- projectId: (_36 = data.data.projectId) === null || _36 === void 0 ? void 0 : _36.toString(),
295
- statusPageId: (_37 = data.data.statusPageId) === null || _37 === void 0 ? void 0 : _37.toString(),
296
- });
297
421
  return { createBy: data, carryForward: statuspage };
298
422
  }
423
+ /*
424
+ * Unsubscribed At follows Is Unsubscribed on every write that sets it - a
425
+ * teammate's toggle on the dashboard, the API, a workflow - not only on the
426
+ * unsubscribe link, which sets both itself (see unsubscribe()).
427
+ *
428
+ * Which rows an update cancels has to be known before it runs: afterwards
429
+ * every matched row reads unsubscribed, and a row that already was would
430
+ * get today's date for a cancellation that happened long ago (or before the
431
+ * column existed). The stamp itself is written after the update, as root,
432
+ * by a plain UPDATE: through updateBy it would be a second update of the
433
+ * row and fire the "on update" workflow trigger a second time.
434
+ */
435
+ async onBeforeUpdate(updateBy) {
436
+ var _a;
437
+ const isUnsubscribed = (_a = updateBy.data) === null || _a === void 0 ? void 0 : _a["isUnsubscribed"];
438
+ const carryForward = {
439
+ isUnsubscribed: typeof isUnsubscribed === "boolean" ? isUnsubscribed : null,
440
+ subscriberIdsBeingUnsubscribed: [],
441
+ };
442
+ if (carryForward.isUnsubscribed === true) {
443
+ const matched = await this.findBy({
444
+ query: updateBy.query,
445
+ select: {
446
+ _id: true,
447
+ isUnsubscribed: true,
448
+ },
449
+ skip: 0,
450
+ limit: LIMIT_MAX,
451
+ props: {
452
+ isRoot: true,
453
+ ignoreHooks: true,
454
+ },
455
+ });
456
+ carryForward.subscriberIdsBeingUnsubscribed = matched
457
+ .filter((subscriber) => {
458
+ return Boolean(subscriber._id) && subscriber.isUnsubscribed !== true;
459
+ })
460
+ .map((subscriber) => {
461
+ return subscriber._id.toString();
462
+ });
463
+ }
464
+ return { updateBy, carryForward };
465
+ }
466
+ async onUpdateSuccess(onUpdate, updatedItemIds) {
467
+ const carryForward = onUpdate.carryForward;
468
+ if (!carryForward || carryForward.isUnsubscribed === null) {
469
+ return onUpdate;
470
+ }
471
+ const updatedIds = updatedItemIds.map((id) => {
472
+ return id.toString();
473
+ });
474
+ if (carryForward.isUnsubscribed === true) {
475
+ const cancelledIds = carryForward.subscriberIdsBeingUnsubscribed.filter((id) => {
476
+ return updatedIds.includes(id);
477
+ });
478
+ if (cancelledIds.length > 0) {
479
+ await this.getRepository().manager.query(`UPDATE "StatusPageSubscriber" SET "unsubscribedAt" = $1 WHERE "_id" = ANY($2::uuid[]) AND "isUnsubscribed" = true AND "unsubscribedAt" IS NULL`, [OneUptimeDate.getCurrentDate(), cancelledIds]);
480
+ }
481
+ return onUpdate;
482
+ }
483
+ // Subscribed again: the old date no longer describes this subscription.
484
+ if (updatedIds.length > 0) {
485
+ await this.getRepository().manager.query(`UPDATE "StatusPageSubscriber" SET "unsubscribedAt" = NULL WHERE "_id" = ANY($1::uuid[]) AND "isUnsubscribed" = false AND "unsubscribedAt" IS NOT NULL`, [updatedIds]);
486
+ }
487
+ return onUpdate;
488
+ }
489
+ /*
490
+ * Cancel a subscription, once. Returns whether this call cancelled it:
491
+ * false when it was already cancelled (or does not exist), which makes the
492
+ * unsubscribe link idempotent.
493
+ *
494
+ * ONE STATEMENT, ON PURPOSE: the WHERE clause's `"isUnsubscribed" = false`
495
+ * lets Postgres decide which of two simultaneous requests - a double click,
496
+ * a mail client that follows the confirmation twice - cancels the
497
+ * subscription, so its Unsubscribed At is written once and the team is told
498
+ * once. `RETURNING` is what tells this call whether it was the one.
499
+ *
500
+ * Written as raw SQL because no DatabaseService write both takes that
501
+ * predicate and reports what it matched. That skips the update hooks, so
502
+ * the "on update" workflow trigger and the realtime event a DatabaseService
503
+ * update fires are fired here, by hand, with the two columns this wrote.
504
+ */
505
+ async unsubscribe(data) {
506
+ var _a;
507
+ const unsubscribedAt = OneUptimeDate.getCurrentDate();
508
+ const rows = returnedRows(await this.getRepository().manager.query(`UPDATE "StatusPageSubscriber"
509
+ SET "isUnsubscribed" = true,
510
+ "unsubscribedAt" = $1,
511
+ "updatedAt" = CURRENT_TIMESTAMP
512
+ WHERE "_id" = $2
513
+ AND "isUnsubscribed" = false
514
+ AND "deletedAt" IS NULL
515
+ RETURNING "_id", "projectId"`, [unsubscribedAt, data.subscriberId.toString()]));
516
+ const row = rows[0];
517
+ if (!row || !row["_id"]) {
518
+ return false;
519
+ }
520
+ const projectId = row["projectId"]
521
+ ? new ObjectID(row["projectId"].toString())
522
+ : null;
523
+ if (projectId) {
524
+ if ((_a = this.getModel().enableWorkflowOn) === null || _a === void 0 ? void 0 : _a.update) {
525
+ await this.onTriggerWorkflow(data.subscriberId, projectId, "on-update", {
526
+ updatedFields: {
527
+ isUnsubscribed: true,
528
+ unsubscribedAt: unsubscribedAt.toISOString(),
529
+ },
530
+ });
531
+ }
532
+ await this.onTriggerRealtime(data.subscriberId, projectId, ModelEventType.Update);
533
+ }
534
+ /*
535
+ * The subscription is cancelled either way; a failure to tell the team
536
+ * must not turn that into an error for the person who asked.
537
+ */
538
+ try {
539
+ await this.notifyTeamOfUnsubscribe({
540
+ subscriberId: data.subscriberId,
541
+ source: data.source,
542
+ unsubscribedAt: unsubscribedAt,
543
+ });
544
+ }
545
+ catch (err) {
546
+ logger.error(err, {
547
+ statusPageSubscriberId: data.subscriberId.toString(),
548
+ });
549
+ }
550
+ return true;
551
+ }
552
+ /*
553
+ * What the status page's unsubscribe page shows for a link, before anything
554
+ * is changed. Opening the page calls this; only a POST unsubscribes.
555
+ *
556
+ * Every way a link can be wrong - a malformed id or token, no such
557
+ * subscriber, a deleted one, one on another status page, a token that does
558
+ * not match - reads the same, Invalid, after the same constant-time token
559
+ * comparison, so the answer cannot be used to tell them apart.
560
+ */
561
+ async getUnsubscribeLinkDetails(data) {
562
+ const subscriber = await this.findSubscriberByUnsubscribeLink(data);
563
+ if (!subscriber) {
564
+ return { state: StatusPageSubscriberUnsubscribeState.Invalid };
565
+ }
566
+ const contact = StatusPageSubscriberUnsubscribe.describeContact(subscriber);
567
+ return {
568
+ state: subscriber.isUnsubscribed
569
+ ? StatusPageSubscriberUnsubscribeState.Unsubscribed
570
+ : StatusPageSubscriberUnsubscribeState.Subscribed,
571
+ channel: contact === null || contact === void 0 ? void 0 : contact.channel,
572
+ contact: contact === null || contact === void 0 ? void 0 : contact.contact,
573
+ wasAddedByTeam: this.isAddedByTeam(subscriber),
574
+ };
575
+ }
576
+ /*
577
+ * The unsubscribe page's POST: cancel the subscription the link belongs to.
578
+ * Idempotent - a second confirmation, or one for a subscription already
579
+ * cancelled some other way, answers Unsubscribed again and changes nothing.
580
+ * A bad link answers Invalid, exactly as getUnsubscribeLinkDetails does.
581
+ */
582
+ async unsubscribeWithLink(data) {
583
+ const subscriber = await this.findSubscriberByUnsubscribeLink(data);
584
+ if (!subscriber || !subscriber.id) {
585
+ return StatusPageSubscriberUnsubscribeState.Invalid;
586
+ }
587
+ if (!subscriber.isUnsubscribed) {
588
+ await this.unsubscribe({
589
+ subscriberId: subscriber.id,
590
+ source: StatusPageSubscriberUnsubscribeSource.UnsubscribeLink,
591
+ });
592
+ }
593
+ return StatusPageSubscriberUnsubscribeState.Unsubscribed;
594
+ }
595
+ /*
596
+ * The subscriber a link belongs to, or null when the link is not good. The
597
+ * subscriber is found by its primary key, never by the token, and the token
598
+ * is then compared in constant time - a query on the token would let the
599
+ * database's own comparison time a guess. The comparison runs even when
600
+ * there is no subscriber to compare with.
601
+ */
602
+ async findSubscriberByUnsubscribeLink(data) {
603
+ const isWellFormed = ObjectID.isValidUUID(data.statusPageId) &&
604
+ ObjectID.isValidUUID(data.subscriberId);
605
+ const subscriber = isWellFormed
606
+ ? await this.findOneBy({
607
+ query: {
608
+ _id: data.subscriberId,
609
+ statusPageId: new ObjectID(data.statusPageId),
610
+ },
611
+ select: {
612
+ _id: true,
613
+ statusPageId: true,
614
+ unsubscribeToken: true,
615
+ isUnsubscribed: true,
616
+ isAddedByTeam: true,
617
+ createdByUserId: true,
618
+ subscriberEmail: true,
619
+ subscriberPhone: true,
620
+ slackIncomingWebhookUrl: true,
621
+ slackWorkspaceName: true,
622
+ microsoftTeamsIncomingWebhookUrl: true,
623
+ microsoftTeamsWorkspaceName: true,
624
+ subscriberWebhook: true,
625
+ },
626
+ props: {
627
+ isRoot: true,
628
+ ignoreHooks: true,
629
+ },
630
+ })
631
+ : null;
632
+ const tokenMatches = StatusPageSubscriberUnsubscribeToken.matches({
633
+ stored: subscriber === null || subscriber === void 0 ? void 0 : subscriber.unsubscribeToken,
634
+ presented: data.token,
635
+ });
636
+ if (!subscriber || !tokenMatches) {
637
+ return null;
638
+ }
639
+ return subscriber;
640
+ }
641
+ /*
642
+ * Tell the team that a subscriber it added has unsubscribed itself (see
643
+ * StatusPageSubscriberUnsubscribeNotice for why). Subscribers people signed
644
+ * up for themselves on the status page tell nobody.
645
+ *
646
+ * A subscriber the team added is one with Is Added By Team - from the
647
+ * dashboard, with an API key or by a workflow - or, created before that
648
+ * column, with a creator (see isAddedByTeam).
649
+ *
650
+ * It goes to the status page's owners - its owner users and the members of
651
+ * its owner teams - and to the teammate who added the subscriber, when a
652
+ * teammate did, each once and only while they are still members of the
653
+ * project, as one plain email through MailService rather than a
654
+ * notification rule: it is about a subscriber list, not an event anyone is
655
+ * on call for. A page with no owners tells only the teammate who added the
656
+ * subscriber; one an API key or a workflow added, on a page with no owners,
657
+ * tells nobody.
658
+ */
659
+ async notifyTeamOfUnsubscribe(data) {
660
+ var _a, _b, _c;
661
+ const subscriber = await this.findOneById({
662
+ id: data.subscriberId,
663
+ select: {
664
+ _id: true,
665
+ projectId: true,
666
+ statusPageId: true,
667
+ isAddedByTeam: true,
668
+ createdByUserId: true,
669
+ createdAt: true,
670
+ subscriberEmail: true,
671
+ subscriberPhone: true,
672
+ slackIncomingWebhookUrl: true,
673
+ slackWorkspaceName: true,
674
+ microsoftTeamsIncomingWebhookUrl: true,
675
+ microsoftTeamsWorkspaceName: true,
676
+ subscriberWebhook: true,
677
+ },
678
+ props: {
679
+ isRoot: true,
680
+ ignoreHooks: true,
681
+ },
682
+ });
683
+ if (!subscriber ||
684
+ !this.isAddedByTeam(subscriber) ||
685
+ !subscriber.projectId ||
686
+ !subscriber.statusPageId) {
687
+ return;
688
+ }
689
+ const contact = StatusPageSubscriberUnsubscribe.describeContact(subscriber, {
690
+ maskPhone: false,
691
+ });
692
+ if (!contact) {
693
+ return;
694
+ }
695
+ const statusPage = await StatusPageService.findOneById({
696
+ id: subscriber.statusPageId,
697
+ select: {
698
+ _id: true,
699
+ name: true,
700
+ pageTitle: true,
701
+ },
702
+ props: {
703
+ isRoot: true,
704
+ ignoreHooks: true,
705
+ },
706
+ });
707
+ if (!statusPage) {
708
+ return;
709
+ }
710
+ // Only a teammate's create has a creator; an API key's or a workflow's does not.
711
+ const creator = subscriber.createdByUserId
712
+ ? await UserService.findOneById({
713
+ id: subscriber.createdByUserId,
714
+ select: {
715
+ _id: true,
716
+ name: true,
717
+ email: true,
718
+ },
719
+ props: {
720
+ isRoot: true,
721
+ },
722
+ })
723
+ : null;
724
+ const candidates = [
725
+ ...(await StatusPageService.findOwners(subscriber.statusPageId)),
726
+ ...(creator ? [creator] : []),
727
+ ];
728
+ const recipients = [];
729
+ const seenUserIds = new Set();
730
+ for (const user of await TeamMemberService.filterUsersToProjectMembers({
731
+ projectId: subscriber.projectId,
732
+ users: candidates,
733
+ })) {
734
+ const userId = ((_a = user.id) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase()) || "";
735
+ if (!userId || !user.email || seenUserIds.has(userId)) {
736
+ continue;
737
+ }
738
+ seenUserIds.add(userId);
739
+ recipients.push(user);
740
+ }
741
+ if (recipients.length === 0) {
742
+ return;
743
+ }
744
+ if (!(await this.isFirstUnsubscribeNoticeInWindow(subscriber.id))) {
745
+ logger.debug(`The team was told about subscriber ${subscriber.id.toString()} unsubscribing within the last ${StatusPageSubscriberUnsubscribeNotice.noticeWindowInHours} hours; not telling it again.`, {
746
+ projectId: subscriber.projectId.toString(),
747
+ statusPageId: subscriber.statusPageId.toString(),
748
+ });
749
+ return;
750
+ }
751
+ const subscriberListUrl = (await StatusPageService.getStatusPageLinkInDashboard(subscriber.projectId, subscriber.statusPageId))
752
+ .addRoute(`/${StatusPageSubscriberUnsubscribeNotice.getSubscriberListRoute(contact.channel)}`)
753
+ .toString();
754
+ const email = StatusPageSubscriberUnsubscribeNotice.build({
755
+ statusPageName: statusPage.name || statusPage.pageTitle || "Status Page",
756
+ contact: contact,
757
+ source: data.source,
758
+ unsubscribedAt: data.unsubscribedAt,
759
+ addedByName: ((_b = creator === null || creator === void 0 ? void 0 : creator.name) === null || _b === void 0 ? void 0 : _b.toString()) || ((_c = creator === null || creator === void 0 ? void 0 : creator.email) === null || _c === void 0 ? void 0 : _c.toString()),
760
+ addedAt: subscriber.createdAt,
761
+ subscriberListUrl: subscriberListUrl,
762
+ });
763
+ for (const recipient of recipients) {
764
+ MailService.sendMail({
765
+ toEmail: recipient.email,
766
+ templateType: EmailTemplateType.SimpleMessage,
767
+ vars: {
768
+ subject: email.subject,
769
+ message: email.message,
770
+ },
771
+ subject: email.subject,
772
+ isSubjectLiteral: true,
773
+ }, {
774
+ projectId: subscriber.projectId,
775
+ userId: recipient.id,
776
+ }).catch((err) => {
777
+ var _a, _b;
778
+ logger.error(err, {
779
+ projectId: (_a = subscriber.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
780
+ statusPageId: (_b = subscriber.statusPageId) === null || _b === void 0 ? void 0 : _b.toString(),
781
+ });
782
+ });
783
+ }
784
+ }
785
+ /*
786
+ * The team is told about a subscriber unsubscribing at most once per
787
+ * window. The public manage page both re-subscribes a subscriber and
788
+ * cancels it again, and it is open to anyone who can see the status page
789
+ * and knows the subscriber's id (it is in the manage link), so without this
790
+ * a loop of the two would email every owner of the page on every turn.
791
+ *
792
+ * One atomic SET NX per subscriber: exactly one notice wins the window
793
+ * however many cancellations arrive together. If the cache cannot be
794
+ * reached the notice goes out: telling the team twice is better than not
795
+ * at all.
796
+ */
797
+ async isFirstUnsubscribeNoticeInWindow(subscriberId) {
798
+ try {
799
+ return await GlobalCache.setStringIfNotExists(StatusPageSubscriberUnsubscribeNotice.noticeCacheNamespace, subscriberId.toString().toLowerCase(), OneUptimeDate.getCurrentDate().toISOString(), {
800
+ expiresInSeconds: StatusPageSubscriberUnsubscribeNotice.noticeWindowInHours * 60 * 60,
801
+ });
802
+ }
803
+ catch (err) {
804
+ logger.warn(`Could not check when the team was last told about subscriber ${subscriberId.toString()} unsubscribing; telling it: ${err instanceof Error ? err.message : String(err)}`);
805
+ return true;
806
+ }
807
+ }
299
808
  async onCreateSuccess(onCreate, createdItem) {
300
809
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
301
- logger.debug("onCreateSuccess called with createdItem:", {
302
- projectId: (_a = createdItem.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
303
- });
304
- logger.debug(createdItem, {
810
+ // Not the item itself: it carries the unsubscribe token.
811
+ logger.debug(`onCreateSuccess called with createdItem ${(_a = createdItem.id) === null || _a === void 0 ? void 0 : _a.toString()}.`, {
305
812
  projectId: (_b = createdItem.projectId) === null || _b === void 0 ? void 0 : _b.toString(),
306
813
  });
307
814
  if (!createdItem.statusPageId) {
@@ -320,15 +827,13 @@ export class Service extends DatabaseService {
320
827
  logger.debug(`Status Page Name: ${statusPageName}`, {
321
828
  projectId: (_e = createdItem.projectId) === null || _e === void 0 ? void 0 : _e.toString(),
322
829
  });
323
- const unsubscribeLink = this.getUnsubscribeLink(URL.fromString(statusPageURL), createdItem.id).toString();
324
- logger.debug(`Unsubscribe Link: ${unsubscribeLink}`, {
325
- projectId: (_f = createdItem.projectId) === null || _f === void 0 ? void 0 : _f.toString(),
326
- });
830
+ // createdItem carries the unsubscribe token onBeforeCreate minted.
831
+ const unsubscribeLink = this.getUnsubscribeLink(URL.fromString(statusPageURL), createdItem).toString();
327
832
  if (createdItem.statusPageId &&
328
833
  createdItem.subscriberPhone &&
329
834
  createdItem._id &&
330
835
  createdItem.sendYouHaveSubscribedMessage) {
331
- logger.debug("Subscriber has a phone number and sendYouHaveSubscribedMessage is true.", { projectId: (_g = createdItem.projectId) === null || _g === void 0 ? void 0 : _g.toString() });
836
+ logger.debug("Subscriber has a phone number and sendYouHaveSubscribedMessage is true.", { projectId: (_f = createdItem.projectId) === null || _f === void 0 ? void 0 : _f.toString() });
332
837
  const statusPage = await StatusPageService.findOneBy({
333
838
  query: {
334
839
  _id: createdItem.statusPageId.toString(),
@@ -349,14 +854,25 @@ export class Service extends DatabaseService {
349
854
  });
350
855
  if (!statusPage) {
351
856
  logger.debug("Status Page not found.", {
352
- projectId: (_h = createdItem.projectId) === null || _h === void 0 ? void 0 : _h.toString(),
857
+ projectId: (_g = createdItem.projectId) === null || _g === void 0 ? void 0 : _g.toString(),
353
858
  });
354
859
  return createdItem;
355
860
  }
356
- logger.debug(`Status Page Call SMS Config: ${JSON.stringify(statusPage.callSmsConfig)}`, { projectId: (_j = createdItem.projectId) === null || _j === void 0 ? void 0 : _j.toString() });
861
+ logger.debug(`Status Page Call SMS Config: ${JSON.stringify(statusPage.callSmsConfig)}`, { projectId: (_h = createdItem.projectId) === null || _h === void 0 ? void 0 : _h.toString() });
862
+ /*
863
+ * On a public status page the SMS keeps the shorter manage link, which
864
+ * works there without signing in: an SMS is billed by the segment (see
865
+ * StatusPageSubscriberUnsubscribe.buildSmsLink).
866
+ */
867
+ const smsUnsubscribeLink = StatusPageSubscriberUnsubscribe.buildSmsLink({
868
+ isPublicStatusPage: (_j = onCreate.carryForward) === null || _j === void 0 ? void 0 : _j.isPublicStatusPage,
869
+ statusPageUrl: statusPageURL,
870
+ subscriberId: createdItem.id,
871
+ unsubscribeUrl: unsubscribeLink,
872
+ });
357
873
  SmsService.sendSms({
358
874
  to: createdItem.subscriberPhone,
359
- message: `You have been subscribed to ${statusPageName}. To unsubscribe, click on the link: ${unsubscribeLink}`,
875
+ message: `You have been subscribed to ${statusPageName}. To unsubscribe, click on the link: ${smsUnsubscribeLink}`,
360
876
  }, {
361
877
  projectId: createdItem.projectId,
362
878
  isSensitive: false,
@@ -402,7 +918,7 @@ export class Service extends DatabaseService {
402
918
  **You have successfully subscribed to receive status updates!**
403
919
 
404
920
  🔗 **Status Page:** [${statusPageName}](${statusPageURL})
405
- 📧 **Manage Subscription:** [Update preferences or unsubscribe](${unsubscribeLink})
921
+ 🔕 **Unsubscribe:** [Stop these notifications](${unsubscribeLink})
406
922
 
407
923
  You will receive real-time notifications for:
408
924
  • Incidents and outages
@@ -480,7 +996,7 @@ Stay informed about service availability! 🚀`;
480
996
  **You have successfully subscribed to receive status updates!**
481
997
 
482
998
  🔗 **Status Page:** [${statusPageName}](${statusPageURL})
483
- 📧 **Manage Subscription:** [Update preferences or unsubscribe](${unsubscribeLink})
999
+ 🔕 **Unsubscribe:** [Stop these notifications](${unsubscribeLink})
484
1000
 
485
1001
  You will receive real-time notifications for:
486
1002
  • Incidents and outages
@@ -537,22 +1053,25 @@ Stay informed about service availability! 🚀`;
537
1053
  projectId: true,
538
1054
  subscriptionConfirmationToken: true,
539
1055
  sendYouHaveSubscribedMessage: true,
1056
+ unsubscribeToken: true,
540
1057
  },
541
1058
  props: {
542
1059
  isRoot: true,
543
1060
  ignoreHooks: true,
544
1061
  },
545
1062
  });
546
- logger.debug(`Found Subscriber: ${JSON.stringify(subscriber)}`, {
547
- statusPageSubscriberId: (_c = data.subscriberId) === null || _c === void 0 ? void 0 : _c.toString(),
1063
+ logger.debug(`Found Subscriber: ${(_c = subscriber === null || subscriber === void 0 ? void 0 : subscriber.id) === null || _c === void 0 ? void 0 : _c.toString()}`, {
1064
+ statusPageSubscriberId: (_d = data.subscriberId) === null || _d === void 0 ? void 0 : _d.toString(),
548
1065
  });
549
1066
  // get status page
550
1067
  if (!subscriber || !subscriber.statusPageId) {
551
1068
  logger.debug("Subscriber or Status Page ID is missing.", {
552
- statusPageSubscriberId: (_d = data.subscriberId) === null || _d === void 0 ? void 0 : _d.toString(),
1069
+ statusPageSubscriberId: (_e = data.subscriberId) === null || _e === void 0 ? void 0 : _e.toString(),
553
1070
  });
554
1071
  return;
555
1072
  }
1073
+ // Its unsubscribe link needs its token (see ensureUnsubscribeTokens).
1074
+ await this.ensureUnsubscribeTokens([subscriber]);
556
1075
  const statusPage = await StatusPageService.findOneBy({
557
1076
  query: {
558
1077
  _id: subscriber.statusPageId.toString(),
@@ -586,46 +1105,43 @@ Stay informed about service availability! 🚀`;
586
1105
  },
587
1106
  });
588
1107
  logger.debug(`Found Status Page: ${JSON.stringify(statusPage)}`, {
589
- statusPageSubscriberId: (_e = data.subscriberId) === null || _e === void 0 ? void 0 : _e.toString(),
1108
+ statusPageSubscriberId: (_f = data.subscriberId) === null || _f === void 0 ? void 0 : _f.toString(),
590
1109
  });
591
1110
  if (!statusPage || !statusPage.id) {
592
1111
  logger.debug("Status Page not found or ID is missing.", {
593
- statusPageSubscriberId: (_f = data.subscriberId) === null || _f === void 0 ? void 0 : _f.toString(),
1112
+ statusPageSubscriberId: (_g = data.subscriberId) === null || _g === void 0 ? void 0 : _g.toString(),
594
1113
  });
595
1114
  return;
596
1115
  }
597
1116
  const statusPageURL = await StatusPageService.getStatusPageURL(statusPage.id);
598
1117
  logger.debug(`Status Page URL: ${statusPageURL}`, {
599
- statusPageSubscriberId: (_g = data.subscriberId) === null || _g === void 0 ? void 0 : _g.toString(),
1118
+ statusPageSubscriberId: (_h = data.subscriberId) === null || _h === void 0 ? void 0 : _h.toString(),
600
1119
  });
601
1120
  const statusPageName = statusPage.pageTitle || statusPage.name || "Status Page";
602
1121
  logger.debug(`Status Page Name: ${statusPageName}`, {
603
- statusPageSubscriberId: (_h = data.subscriberId) === null || _h === void 0 ? void 0 : _h.toString(),
1122
+ statusPageSubscriberId: (_j = data.subscriberId) === null || _j === void 0 ? void 0 : _j.toString(),
604
1123
  });
605
1124
  const host = await DatabaseConfig.getHost();
606
1125
  logger.debug(`Host: ${host}`, {
607
- statusPageSubscriberId: (_j = data.subscriberId) === null || _j === void 0 ? void 0 : _j.toString(),
1126
+ statusPageSubscriberId: (_k = data.subscriberId) === null || _k === void 0 ? void 0 : _k.toString(),
608
1127
  });
609
1128
  const httpProtocol = await DatabaseConfig.getHttpProtocol();
610
1129
  logger.debug(`HTTP Protocol: ${httpProtocol}`, {
611
- statusPageSubscriberId: (_k = data.subscriberId) === null || _k === void 0 ? void 0 : _k.toString(),
1130
+ statusPageSubscriberId: (_l = data.subscriberId) === null || _l === void 0 ? void 0 : _l.toString(),
612
1131
  });
613
- const statusPageIdString = ((_l = statusPage.id) === null || _l === void 0 ? void 0 : _l.toString()) || ((_m = statusPage._id) === null || _m === void 0 ? void 0 : _m.toString()) || null;
1132
+ const statusPageIdString = ((_m = statusPage.id) === null || _m === void 0 ? void 0 : _m.toString()) || ((_o = statusPage._id) === null || _o === void 0 ? void 0 : _o.toString()) || null;
614
1133
  const confirmSubscriptionLink = this.getConfirmSubscriptionLink({
615
1134
  statusPageUrl: statusPageURL,
616
1135
  confirmationToken: subscriber.subscriptionConfirmationToken || "",
617
1136
  statusPageSubscriberId: subscriber.id,
618
1137
  }).toString();
619
1138
  logger.debug(`Confirm Subscription Link: ${confirmSubscriptionLink}`, {
620
- statusPageSubscriberId: (_o = data.subscriberId) === null || _o === void 0 ? void 0 : _o.toString(),
1139
+ statusPageSubscriberId: (_p = data.subscriberId) === null || _p === void 0 ? void 0 : _p.toString(),
621
1140
  });
622
1141
  if (subscriber.statusPageId &&
623
1142
  subscriber.subscriberEmail &&
624
1143
  subscriber._id) {
625
- const unsubscribeUrl = this.getUnsubscribeLink(URL.fromString(statusPageURL), subscriber.id).toString();
626
- logger.debug(`Unsubscribe URL: ${unsubscribeUrl}`, {
627
- statusPageSubscriberId: (_p = data.subscriberId) === null || _p === void 0 ? void 0 : _p.toString(),
628
- });
1144
+ const unsubscribeUrl = this.getUnsubscribeLink(URL.fromString(statusPageURL), subscriber).toString();
629
1145
  const customTemplate = await StatusPageSubscriberNotificationTemplateService.getTemplateForStatusPage({
630
1146
  statusPageId: statusPage.id,
631
1147
  eventType: StatusPageSubscriberNotificationEventType.SubscriberSubscriptionConfirmation,
@@ -643,7 +1159,8 @@ Stay informed about service availability! 🚀`;
643
1159
  * pattern used elsewhere — without custom SMTP we keep the styled
644
1160
  * OneUptime default so emails still look right out-of-the-box).
645
1161
  */
646
- const compiledBody = StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(customTemplate.templateBody, templateVariables);
1162
+ // The body is HTML, so the (plain-text) values are escaped into it.
1163
+ const compiledBody = StatusPageSubscriberNotificationTemplateServiceClass.compileEmailBodyTemplate(customTemplate.templateBody, templateVariables);
647
1164
  const compiledSubject = customTemplate.emailSubject
648
1165
  ? StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(customTemplate.emailSubject, templateVariables)
649
1166
  : "Confirm your subscription to " + statusPageName;
@@ -727,22 +1244,25 @@ Stay informed about service availability! 🚀`;
727
1244
  subscriberPhone: true,
728
1245
  projectId: true,
729
1246
  sendYouHaveSubscribedMessage: true,
1247
+ unsubscribeToken: true,
730
1248
  },
731
1249
  props: {
732
1250
  isRoot: true,
733
1251
  ignoreHooks: true,
734
1252
  },
735
1253
  });
736
- logger.debug(`Found Subscriber: ${JSON.stringify(subscriber)}`, {
737
- statusPageSubscriberId: (_c = data.subscriberId) === null || _c === void 0 ? void 0 : _c.toString(),
1254
+ logger.debug(`Found Subscriber: ${(_c = subscriber === null || subscriber === void 0 ? void 0 : subscriber.id) === null || _c === void 0 ? void 0 : _c.toString()}`, {
1255
+ statusPageSubscriberId: (_d = data.subscriberId) === null || _d === void 0 ? void 0 : _d.toString(),
738
1256
  });
739
1257
  // get status page
740
1258
  if (!subscriber || !subscriber.statusPageId) {
741
1259
  logger.debug("Subscriber or Status Page ID is missing.", {
742
- statusPageSubscriberId: (_d = data.subscriberId) === null || _d === void 0 ? void 0 : _d.toString(),
1260
+ statusPageSubscriberId: (_e = data.subscriberId) === null || _e === void 0 ? void 0 : _e.toString(),
743
1261
  });
744
1262
  return;
745
1263
  }
1264
+ // Its unsubscribe link needs its token (see ensureUnsubscribeTokens).
1265
+ await this.ensureUnsubscribeTokens([subscriber]);
746
1266
  const statusPage = await StatusPageService.findOneBy({
747
1267
  query: {
748
1268
  _id: subscriber.statusPageId.toString(),
@@ -776,35 +1296,32 @@ Stay informed about service availability! 🚀`;
776
1296
  },
777
1297
  });
778
1298
  logger.debug(`Found Status Page: ${JSON.stringify(statusPage)}`, {
779
- statusPageSubscriberId: (_e = data.subscriberId) === null || _e === void 0 ? void 0 : _e.toString(),
1299
+ statusPageSubscriberId: (_f = data.subscriberId) === null || _f === void 0 ? void 0 : _f.toString(),
780
1300
  });
781
1301
  if (!statusPage || !statusPage.id) {
782
1302
  logger.debug("Status Page not found or ID is missing.", {
783
- statusPageSubscriberId: (_f = data.subscriberId) === null || _f === void 0 ? void 0 : _f.toString(),
1303
+ statusPageSubscriberId: (_g = data.subscriberId) === null || _g === void 0 ? void 0 : _g.toString(),
784
1304
  });
785
1305
  return;
786
1306
  }
787
1307
  const statusPageURL = await StatusPageService.getStatusPageURL(statusPage.id);
788
1308
  logger.debug(`Status Page URL: ${statusPageURL}`, {
789
- statusPageSubscriberId: (_g = data.subscriberId) === null || _g === void 0 ? void 0 : _g.toString(),
1309
+ statusPageSubscriberId: (_h = data.subscriberId) === null || _h === void 0 ? void 0 : _h.toString(),
790
1310
  });
791
1311
  const statusPageName = statusPage.pageTitle || statusPage.name || "Status Page";
792
1312
  logger.debug(`Status Page Name: ${statusPageName}`, {
793
- statusPageSubscriberId: (_h = data.subscriberId) === null || _h === void 0 ? void 0 : _h.toString(),
1313
+ statusPageSubscriberId: (_j = data.subscriberId) === null || _j === void 0 ? void 0 : _j.toString(),
794
1314
  });
795
1315
  const host = await DatabaseConfig.getHost();
796
1316
  logger.debug(`Host: ${host}`, {
797
- statusPageSubscriberId: (_j = data.subscriberId) === null || _j === void 0 ? void 0 : _j.toString(),
1317
+ statusPageSubscriberId: (_k = data.subscriberId) === null || _k === void 0 ? void 0 : _k.toString(),
798
1318
  });
799
1319
  const httpProtocol = await DatabaseConfig.getHttpProtocol();
800
1320
  logger.debug(`HTTP Protocol: ${httpProtocol}`, {
801
- statusPageSubscriberId: (_k = data.subscriberId) === null || _k === void 0 ? void 0 : _k.toString(),
802
- });
803
- const statusPageIdString = ((_l = statusPage.id) === null || _l === void 0 ? void 0 : _l.toString()) || ((_m = statusPage._id) === null || _m === void 0 ? void 0 : _m.toString()) || null;
804
- const unsubscribeLink = this.getUnsubscribeLink(URL.fromString(statusPageURL), subscriber.id).toString();
805
- logger.debug(`Unsubscribe Link: ${unsubscribeLink}`, {
806
- statusPageSubscriberId: (_o = data.subscriberId) === null || _o === void 0 ? void 0 : _o.toString(),
1321
+ statusPageSubscriberId: (_l = data.subscriberId) === null || _l === void 0 ? void 0 : _l.toString(),
807
1322
  });
1323
+ const statusPageIdString = ((_m = statusPage.id) === null || _m === void 0 ? void 0 : _m.toString()) || ((_o = statusPage._id) === null || _o === void 0 ? void 0 : _o.toString()) || null;
1324
+ const unsubscribeLink = this.getUnsubscribeLink(URL.fromString(statusPageURL), subscriber).toString();
808
1325
  if (subscriber.statusPageId &&
809
1326
  subscriber.subscriberEmail &&
810
1327
  subscriber._id) {
@@ -822,7 +1339,8 @@ Stay informed about service availability! 🚀`;
822
1339
  unsubscribeUrl: unsubscribeLink,
823
1340
  };
824
1341
  if ((customTemplate === null || customTemplate === void 0 ? void 0 : customTemplate.templateBody) && statusPage.smtpConfig) {
825
- const compiledBody = StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(customTemplate.templateBody, templateVariables);
1342
+ // The body is HTML, so the (plain-text) values are escaped into it.
1343
+ const compiledBody = StatusPageSubscriberNotificationTemplateServiceClass.compileEmailBodyTemplate(customTemplate.templateBody, templateVariables);
826
1344
  const compiledSubject = customTemplate.emailSubject
827
1345
  ? StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(customTemplate.emailSubject, templateVariables)
828
1346
  : "You have been subscribed to " + statusPageName;
@@ -903,7 +1421,19 @@ Stay informed about service availability! 🚀`;
903
1421
  });
904
1422
  return confirmSubscriptionLink;
905
1423
  }
906
- async getSubscribersByStatusPage(statusPageId, props) {
1424
+ /*
1425
+ * The confirmed, still-subscribed subscribers of a status page, in _id
1426
+ * order, at most `limit` (LIMIT_MAX by default) of them.
1427
+ *
1428
+ * One read stops at the limit, so a page with more subscribers than that
1429
+ * is read in batches: pass the _id of the last subscriber of one batch as
1430
+ * `afterId` to read the next, until a batch comes back smaller than the
1431
+ * limit (SubscriberNotificationFanOut does this for the subscriber jobs).
1432
+ * The cursor is an _id rather than an offset, so a subscriber who
1433
+ * unsubscribes while a send is part-way through cannot shift the rows
1434
+ * after it into a batch already read, and nobody is skipped.
1435
+ */
1436
+ async getSubscribersByStatusPage(statusPageId, props, options) {
907
1437
  logger.debug("getSubscribersByStatusPage called with statusPageId:", {
908
1438
  statusPageId: statusPageId === null || statusPageId === void 0 ? void 0 : statusPageId.toString(),
909
1439
  });
@@ -917,11 +1447,9 @@ Stay informed about service availability! 🚀`;
917
1447
  statusPageId: statusPageId === null || statusPageId === void 0 ? void 0 : statusPageId.toString(),
918
1448
  });
919
1449
  const subscribers = await this.findBy({
920
- query: {
921
- statusPageId: statusPageId,
922
- isUnsubscribed: false,
923
- isSubscriptionConfirmed: true,
924
- },
1450
+ query: Object.assign({ statusPageId: statusPageId, isUnsubscribed: false, isSubscriptionConfirmed: true }, ((options === null || options === void 0 ? void 0 : options.afterId)
1451
+ ? { _id: QueryHelper.greaterThan(options.afterId) }
1452
+ : {})),
925
1453
  select: {
926
1454
  _id: true,
927
1455
  subscriberEmail: true,
@@ -933,53 +1461,278 @@ Stay informed about service availability! 🚀`;
933
1461
  statusPageResources: true,
934
1462
  isSubscribedToAllEventTypes: true,
935
1463
  statusPageEventTypes: true,
1464
+ // Every sender puts this subscriber's unsubscribe link in its message.
1465
+ unsubscribeToken: true,
1466
+ /*
1467
+ * Whether the team added this subscriber rather than it signing up
1468
+ * on the status page (see isAddedByTeam).
1469
+ */
1470
+ isAddedByTeam: true,
1471
+ createdByUserId: true,
1472
+ },
1473
+ // A stable order, which the afterId cursor reads on from.
1474
+ sort: {
1475
+ _id: SortOrder.Ascending,
936
1476
  },
937
1477
  skip: 0,
938
- limit: LIMIT_MAX,
1478
+ limit: (options === null || options === void 0 ? void 0 : options.limit) || LIMIT_MAX,
939
1479
  props: props,
940
1480
  });
941
- logger.debug("Found subscribers:", {
942
- statusPageId: statusPageId === null || statusPageId === void 0 ? void 0 : statusPageId.toString(),
943
- });
944
- logger.debug(subscribers, {
1481
+ await this.ensureUnsubscribeTokens(subscribers);
1482
+ /*
1483
+ * The count, not the rows: each row now carries its unsubscribe token,
1484
+ * which is a credential and has no place in a log line.
1485
+ */
1486
+ logger.debug(`Found ${subscribers.length} subscribers.`, {
945
1487
  statusPageId: statusPageId === null || statusPageId === void 0 ? void 0 : statusPageId.toString(),
946
1488
  });
947
1489
  return subscribers;
948
1490
  }
949
- getUnsubscribeLink(statusPageUrl, statusPageSubscriberId) {
950
- logger.debug("getUnsubscribeLink called with statusPageUrl:", {
951
- statusPageSubscriberId: statusPageSubscriberId === null || statusPageSubscriberId === void 0 ? void 0 : statusPageSubscriberId.toString(),
952
- });
953
- logger.debug(statusPageUrl, {
954
- statusPageSubscriberId: statusPageSubscriberId === null || statusPageSubscriberId === void 0 ? void 0 : statusPageSubscriberId.toString(),
955
- });
956
- logger.debug("statusPageSubscriberId:", {
957
- statusPageSubscriberId: statusPageSubscriberId === null || statusPageSubscriberId === void 0 ? void 0 : statusPageSubscriberId.toString(),
958
- });
959
- logger.debug(statusPageSubscriberId, {
960
- statusPageSubscriberId: statusPageSubscriberId === null || statusPageSubscriberId === void 0 ? void 0 : statusPageSubscriberId.toString(),
1491
+ /*
1492
+ * How many subscribers of each status page each channel reaches, for the
1493
+ * audience summary shown before an incident or a public note is sent
1494
+ * (IncidentSubscriberAudience). The same subscribers getSubscribersByStatusPage
1495
+ * sends to - confirmed, not unsubscribed - counted per channel in one
1496
+ * aggregate query rather than read out: it never loads an address.
1497
+ *
1498
+ * A channel counts a subscriber whenever the job would send on it, which is
1499
+ * whenever that column holds a value; a subscription with both an email and
1500
+ * a phone counts once on each. Rows are pinned to the project, whatever ids
1501
+ * the caller passes.
1502
+ *
1503
+ * Keyed by the lower-cased status page id. A page with no active subscriber
1504
+ * has no entry.
1505
+ */
1506
+ async countActiveSubscribersByChannel(data) {
1507
+ const counts = {};
1508
+ const statusPageIds = [];
1509
+ for (const statusPageId of data.statusPageIds) {
1510
+ const id = statusPageId.toString().trim().toLowerCase();
1511
+ if (id && !statusPageIds.includes(id)) {
1512
+ statusPageIds.push(id);
1513
+ }
1514
+ }
1515
+ if (statusPageIds.length === 0) {
1516
+ return counts;
1517
+ }
1518
+ const rows = await this.getRepository().manager.query(`SELECT
1519
+ "statusPageId"::text AS "statusPageId",
1520
+ COUNT(*) FILTER (WHERE NULLIF(TRIM("subscriberEmail"), '') IS NOT NULL)::text AS "email",
1521
+ COUNT(*) FILTER (WHERE NULLIF(TRIM("subscriberPhone"), '') IS NOT NULL)::text AS "sms",
1522
+ COUNT(*) FILTER (WHERE NULLIF(TRIM("slackIncomingWebhookUrl"), '') IS NOT NULL)::text AS "slack",
1523
+ COUNT(*) FILTER (WHERE NULLIF(TRIM("microsoftTeamsIncomingWebhookUrl"), '') IS NOT NULL)::text AS "microsoftTeams",
1524
+ COUNT(*) FILTER (WHERE NULLIF(TRIM("subscriberWebhook"), '') IS NOT NULL)::text AS "webhook"
1525
+ FROM "StatusPageSubscriber"
1526
+ WHERE "projectId" = $1
1527
+ AND "statusPageId" = ANY($2::uuid[])
1528
+ AND "isUnsubscribed" = false
1529
+ AND "isSubscriptionConfirmed" = true
1530
+ AND "deletedAt" IS NULL
1531
+ GROUP BY "statusPageId"`, [data.projectId.toString(), statusPageIds]);
1532
+ const toCount = (value) => {
1533
+ const count = parseInt(value || "0", 10);
1534
+ return Number.isFinite(count) && count > 0 ? count : 0;
1535
+ };
1536
+ for (const row of rows) {
1537
+ counts[row.statusPageId.toLowerCase()] = {
1538
+ email: toCount(row.email),
1539
+ sms: toCount(row.sms),
1540
+ slack: toCount(row.slack),
1541
+ microsoftTeams: toCount(row.microsoftTeams),
1542
+ webhook: toCount(row.webhook),
1543
+ };
1544
+ }
1545
+ return counts;
1546
+ }
1547
+ /*
1548
+ * The link to a subscriber's unsubscribe page, which every notification to
1549
+ * it carries: {statusPageUrl}/unsubscribe/{id}-{token}. It works on public
1550
+ * and private status pages alike and without signing in, and it only ever
1551
+ * asks - the page unsubscribes when its reader confirms (see
1552
+ * Common/Types/StatusPage/StatusPageSubscriberUnsubscribe).
1553
+ *
1554
+ * Pass the subscriber read with its unsubscribeToken: every loader that
1555
+ * feeds a sender selects it (getSubscribersByStatusPage and the subscribe
1556
+ * and manage emails). A subscriber without one still gets a link, to the
1557
+ * page that says the link is out of date, rather than none; that is logged,
1558
+ * because only a subscriber created around the migration that added the
1559
+ * token, or one written with hooks skipped, can lack it.
1560
+ */
1561
+ getUnsubscribeLink(statusPageUrl, subscriber) {
1562
+ const subscriberId = subscriber.id;
1563
+ if (!subscriberId) {
1564
+ throw new BadDataException("A subscriber id is required to build an unsubscribe link.");
1565
+ }
1566
+ if (!StatusPageSubscriberUnsubscribe.isWellFormedToken(subscriber.unsubscribeToken)) {
1567
+ logger.error(`Status page subscriber ${subscriberId.toString()} has no unsubscribe token; its unsubscribe link leads to the out-of-date link page.`, {
1568
+ statusPageSubscriberId: subscriberId.toString(),
1569
+ });
1570
+ }
1571
+ return StatusPageSubscriberUnsubscribe.buildLink({
1572
+ statusPageUrl: statusPageUrl,
1573
+ subscriberId: subscriberId,
1574
+ unsubscribeToken: subscriber.unsubscribeToken,
961
1575
  });
962
- const unsubscribeLink = URL.fromString(statusPageUrl.toString()).addRoute("/update-subscription/" + statusPageSubscriberId.toString());
963
- logger.debug("Generated Unsubscribe Link:", {
964
- statusPageSubscriberId: statusPageSubscriberId === null || statusPageSubscriberId === void 0 ? void 0 : statusPageSubscriberId.toString(),
1576
+ }
1577
+ /*
1578
+ * The subscriber's Update Subscription page, where it can choose resources
1579
+ * and event types (and unsubscribe). The "manage your subscription" email a
1580
+ * visitor asks for from the Subscribe page links here. On a private status
1581
+ * page it needs a signed-in visitor, like the rest of the page.
1582
+ */
1583
+ getManageSubscriptionLink(statusPageUrl, statusPageSubscriberId) {
1584
+ return StatusPageSubscriberUnsubscribe.buildManageSubscriptionLink({
1585
+ statusPageUrl: statusPageUrl,
1586
+ subscriberId: statusPageSubscriberId,
965
1587
  });
966
- logger.debug(unsubscribeLink, {
967
- statusPageSubscriberId: statusPageSubscriberId === null || statusPageSubscriberId === void 0 ? void 0 : statusPageSubscriberId.toString(),
1588
+ }
1589
+ /*
1590
+ * Give every subscriber in the list an unsubscribe token it lacks, in place,
1591
+ * so the links built from them work. Every create mints one, and the
1592
+ * BackfillStatusPageSubscriberUnsubscribeColumns data migration gives one
1593
+ * to every subscriber that existed before; this covers the ones that
1594
+ * migration has not reached yet (it runs after the upgrade, in batches), a
1595
+ * subscriber created in between, and one written with hooks skipped.
1596
+ *
1597
+ * One statement per batch of subscribers, not per subscriber: until the
1598
+ * backfill has run, a whole page's list can be missing its tokens.
1599
+ *
1600
+ * The write only fills an empty column, so two senders racing on the same
1601
+ * subscriber - or a sender and the backfill - cannot hand out two different
1602
+ * tokens: the loser reads back the winner's.
1603
+ */
1604
+ async ensureUnsubscribeTokens(subscribers) {
1605
+ // The rows that lack one, by id: a list can hold the same subscriber twice.
1606
+ const missing = new Map();
1607
+ for (const subscriber of subscribers) {
1608
+ if (!subscriber._id ||
1609
+ StatusPageSubscriberUnsubscribe.isWellFormedToken(subscriber.unsubscribeToken)) {
1610
+ continue;
1611
+ }
1612
+ const id = subscriber._id.toString().toLowerCase();
1613
+ missing.set(id, [...(missing.get(id) || []), subscriber]);
1614
+ }
1615
+ const ids = Array.from(missing.keys());
1616
+ for (let start = 0; start < ids.length; start += UNSUBSCRIBE_COLUMNS_BATCH_SIZE) {
1617
+ const batch = ids.slice(start, start + UNSUBSCRIBE_COLUMNS_BATCH_SIZE);
1618
+ await this.fillMissingUnsubscribeTokens(batch);
1619
+ const stored = await this.findBy({
1620
+ query: {
1621
+ _id: QueryHelper.any(batch),
1622
+ },
1623
+ select: {
1624
+ _id: true,
1625
+ unsubscribeToken: true,
1626
+ },
1627
+ skip: 0,
1628
+ limit: batch.length,
1629
+ props: {
1630
+ isRoot: true,
1631
+ ignoreHooks: true,
1632
+ },
1633
+ });
1634
+ for (const row of stored) {
1635
+ if (!row._id ||
1636
+ !StatusPageSubscriberUnsubscribe.isWellFormedToken(row.unsubscribeToken)) {
1637
+ continue;
1638
+ }
1639
+ for (const subscriber of missing.get(row._id.toString().toLowerCase()) || []) {
1640
+ subscriber.unsubscribeToken = row.unsubscribeToken;
1641
+ }
1642
+ }
1643
+ }
1644
+ }
1645
+ /*
1646
+ * The BackfillStatusPageSubscriberUnsubscribeColumns data migration: give
1647
+ * every subscriber that existed before the upgrade its unsubscribe token,
1648
+ * and mark the ones with a creator as added by the team (Is Added By
1649
+ * Team). Soft-deleted subscribers are included: one that is restored must
1650
+ * not come back without a token.
1651
+ *
1652
+ * The table is walked in primary key order, a batch of ids at a time, and
1653
+ * each batch is written by primary key in short statements of their own.
1654
+ * So however large the table, no statement holds its rows for long or runs
1655
+ * into the connection's statement timeout, and notifications, sign-ups and
1656
+ * the subscriber lists carry on while it runs - which one UPDATE of every
1657
+ * row, in the migration that added the columns, would have stopped.
1658
+ *
1659
+ * Idempotent, and safe to run twice at once (the data migration runner is
1660
+ * not serialized): every write only fills what is still empty, and
1661
+ * re-checks that under the row lock, so a token a sender has already put
1662
+ * in a message is never replaced.
1663
+ */
1664
+ async backfillUnsubscribeColumns(options) {
1665
+ const batchSize = Math.max(1, Math.floor((options === null || options === void 0 ? void 0 : options.batchSize) || UNSUBSCRIBE_COLUMNS_BATCH_SIZE));
1666
+ const result = {
1667
+ tokensGiven: 0,
1668
+ markedAddedByTeam: 0,
1669
+ };
1670
+ let lastId = null;
1671
+ for (;;) {
1672
+ const rows = await this.getRepository().manager.query(`SELECT "_id"::text AS "_id",
1673
+ ("unsubscribeToken" IS NULL) AS "needsToken",
1674
+ ("isAddedByTeam" = false AND "createdByUserId" IS NOT NULL) AS "needsAddedByTeam"
1675
+ FROM "StatusPageSubscriber"
1676
+ WHERE ($2::uuid IS NULL OR "_id" > $2::uuid)
1677
+ ORDER BY "_id" ASC
1678
+ LIMIT $1`, [batchSize, lastId]);
1679
+ if (rows.length === 0) {
1680
+ break;
1681
+ }
1682
+ const needToken = rows
1683
+ .filter((row) => {
1684
+ return row.needsToken === true;
1685
+ })
1686
+ .map((row) => {
1687
+ return row._id;
1688
+ });
1689
+ const needAddedByTeam = rows
1690
+ .filter((row) => {
1691
+ return row.needsAddedByTeam === true;
1692
+ })
1693
+ .map((row) => {
1694
+ return row._id;
1695
+ });
1696
+ result.tokensGiven += await this.fillMissingUnsubscribeTokens(needToken);
1697
+ if (needAddedByTeam.length > 0) {
1698
+ result.markedAddedByTeam += affectedRowCount(await this.getRepository().manager.query(`UPDATE "StatusPageSubscriber" SET "isAddedByTeam" = true WHERE "_id" = ANY($1::uuid[]) AND "createdByUserId" IS NOT NULL AND "isAddedByTeam" = false`, [needAddedByTeam]));
1699
+ }
1700
+ lastId = rows[rows.length - 1]._id;
1701
+ if (rows.length < batchSize) {
1702
+ break;
1703
+ }
1704
+ }
1705
+ return result;
1706
+ }
1707
+ /*
1708
+ * Mint a token, from Node's CSPRNG like every other, for each of these
1709
+ * subscribers that has none, in one statement. Returns how many were given
1710
+ * one. `"unsubscribeToken" IS NULL` is checked again under each row's lock,
1711
+ * so a token another writer stored first is kept.
1712
+ */
1713
+ async fillMissingUnsubscribeTokens(subscriberIds) {
1714
+ if (subscriberIds.length === 0) {
1715
+ return 0;
1716
+ }
1717
+ const tokens = subscriberIds.map(() => {
1718
+ return StatusPageSubscriberUnsubscribeToken.generate();
968
1719
  });
969
- return unsubscribeLink;
1720
+ return affectedRowCount(await this.getRepository().manager.query(`UPDATE "StatusPageSubscriber" AS "subscriber" SET "unsubscribeToken" = "minted"."token" FROM unnest($1::uuid[], $2::text[]) AS "minted"("id", "token") WHERE "subscriber"."_id" = "minted"."id" AND "subscriber"."unsubscribeToken" IS NULL`, [subscriberIds, tokens]));
970
1721
  }
971
1722
  shouldSendNotification(data) {
972
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1;
973
- logger.debug("shouldSendNotification called with data:", {
974
- statusPageId: (_b = (_a = data.statusPage) === null || _a === void 0 ? void 0 : _a.id) === null || _b === void 0 ? void 0 : _b.toString(),
975
- });
976
- logger.debug(data, {
977
- statusPageId: (_d = (_c = data.statusPage) === null || _c === void 0 ? void 0 : _c.id) === null || _d === void 0 ? void 0 : _d.toString(),
1723
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
1724
+ /*
1725
+ * Ids only: the subscriber carries its unsubscribe token, which is a
1726
+ * credential (it cancels the subscription, private pages included), and
1727
+ * every subscriber job calls this for every subscriber.
1728
+ */
1729
+ logger.debug(`shouldSendNotification called for subscriber ${((_b = (_a = data.subscriber) === null || _a === void 0 ? void 0 : _a._id) === null || _b === void 0 ? void 0 : _b.toString()) || ""} (${data.eventType}, ${((_c = data.statusPageResources) === null || _c === void 0 ? void 0 : _c.length) || 0} resource(s)).`, {
1730
+ statusPageId: (_e = (_d = data.statusPage) === null || _d === void 0 ? void 0 : _d.id) === null || _e === void 0 ? void 0 : _e.toString(),
978
1731
  });
979
1732
  let shouldSendNotification = true; // default to true.
980
1733
  if (data.subscriber.isUnsubscribed) {
981
1734
  logger.debug("Subscriber is unsubscribed.", {
982
- statusPageId: (_f = (_e = data.statusPage) === null || _e === void 0 ? void 0 : _e.id) === null || _f === void 0 ? void 0 : _f.toString(),
1735
+ statusPageId: (_g = (_f = data.statusPage) === null || _f === void 0 ? void 0 : _f.id) === null || _g === void 0 ? void 0 : _g.toString(),
983
1736
  });
984
1737
  shouldSendNotification = false;
985
1738
  return shouldSendNotification;
@@ -989,29 +1742,29 @@ Stay informed about service availability! 🚀`;
989
1742
  !(data.eventType === StatusPageEventType.Announcement &&
990
1743
  data.statusPageResources.length === 0) // announcements with no monitors don't use resource filtering
991
1744
  ) {
992
- logger.debug("Subscriber can choose resources and is not subscribed to all resources.", { statusPageId: (_h = (_g = data.statusPage) === null || _g === void 0 ? void 0 : _g.id) === null || _h === void 0 ? void 0 : _h.toString() });
993
- const subscriberResourceIds = ((_j = data.subscriber.statusPageResources) === null || _j === void 0 ? void 0 : _j.map((resource) => {
1745
+ logger.debug("Subscriber can choose resources and is not subscribed to all resources.", { statusPageId: (_j = (_h = data.statusPage) === null || _h === void 0 ? void 0 : _h.id) === null || _j === void 0 ? void 0 : _j.toString() });
1746
+ const subscriberResourceIds = ((_k = data.subscriber.statusPageResources) === null || _k === void 0 ? void 0 : _k.map((resource) => {
994
1747
  var _a;
995
1748
  return (_a = resource.id) === null || _a === void 0 ? void 0 : _a.toString();
996
1749
  })) || [];
997
1750
  logger.debug(`Subscriber Resource IDs: ${subscriberResourceIds}`, {
998
- statusPageId: (_l = (_k = data.statusPage) === null || _k === void 0 ? void 0 : _k.id) === null || _l === void 0 ? void 0 : _l.toString(),
1751
+ statusPageId: (_m = (_l = data.statusPage) === null || _l === void 0 ? void 0 : _l.id) === null || _m === void 0 ? void 0 : _m.toString(),
999
1752
  });
1000
1753
  let shouldSendNotificationForResource = false;
1001
1754
  if (subscriberResourceIds.length === 0) {
1002
1755
  logger.debug("Subscriber has no resource IDs.", {
1003
- statusPageId: (_o = (_m = data.statusPage) === null || _m === void 0 ? void 0 : _m.id) === null || _o === void 0 ? void 0 : _o.toString(),
1756
+ statusPageId: (_p = (_o = data.statusPage) === null || _o === void 0 ? void 0 : _o.id) === null || _p === void 0 ? void 0 : _p.toString(),
1004
1757
  });
1005
1758
  shouldSendNotificationForResource = false;
1006
1759
  }
1007
1760
  else {
1008
1761
  for (const resource of data.statusPageResources) {
1009
1762
  logger.debug(`Checking resource: ${resource.id}`, {
1010
- statusPageId: (_q = (_p = data.statusPage) === null || _p === void 0 ? void 0 : _p.id) === null || _q === void 0 ? void 0 : _q.toString(),
1763
+ statusPageId: (_r = (_q = data.statusPage) === null || _q === void 0 ? void 0 : _q.id) === null || _r === void 0 ? void 0 : _r.toString(),
1011
1764
  });
1012
- if (subscriberResourceIds.includes((_r = resource.id) === null || _r === void 0 ? void 0 : _r.toString())) {
1765
+ if (subscriberResourceIds.includes((_s = resource.id) === null || _s === void 0 ? void 0 : _s.toString())) {
1013
1766
  logger.debug("Resource ID matches subscriber's resource ID.", {
1014
- statusPageId: (_t = (_s = data.statusPage) === null || _s === void 0 ? void 0 : _s.id) === null || _t === void 0 ? void 0 : _t.toString(),
1767
+ statusPageId: (_u = (_t = data.statusPage) === null || _t === void 0 ? void 0 : _t.id) === null || _u === void 0 ? void 0 : _u.toString(),
1015
1768
  });
1016
1769
  shouldSendNotificationForResource = true;
1017
1770
  }
@@ -1019,7 +1772,7 @@ Stay informed about service availability! 🚀`;
1019
1772
  }
1020
1773
  if (!shouldSendNotificationForResource) {
1021
1774
  logger.debug("Should not send notification for resource.", {
1022
- statusPageId: (_v = (_u = data.statusPage) === null || _u === void 0 ? void 0 : _u.id) === null || _v === void 0 ? void 0 : _v.toString(),
1775
+ statusPageId: (_w = (_v = data.statusPage) === null || _v === void 0 ? void 0 : _v.id) === null || _w === void 0 ? void 0 : _w.toString(),
1023
1776
  });
1024
1777
  shouldSendNotification = false;
1025
1778
  }
@@ -1027,15 +1780,15 @@ Stay informed about service availability! 🚀`;
1027
1780
  // now do for event types
1028
1781
  if (data.statusPage.allowSubscribersToChooseEventTypes &&
1029
1782
  !data.subscriber.isSubscribedToAllEventTypes) {
1030
- logger.debug("Subscriber can choose event types and is not subscribed to all event types.", { statusPageId: (_x = (_w = data.statusPage) === null || _w === void 0 ? void 0 : _w.id) === null || _x === void 0 ? void 0 : _x.toString() });
1783
+ logger.debug("Subscriber can choose event types and is not subscribed to all event types.", { statusPageId: (_y = (_x = data.statusPage) === null || _x === void 0 ? void 0 : _x.id) === null || _y === void 0 ? void 0 : _y.toString() });
1031
1784
  const subscriberEventTypes = data.subscriber.statusPageEventTypes || [];
1032
1785
  logger.debug(`Subscriber Event Types: ${subscriberEventTypes}`, {
1033
- statusPageId: (_z = (_y = data.statusPage) === null || _y === void 0 ? void 0 : _y.id) === null || _z === void 0 ? void 0 : _z.toString(),
1786
+ statusPageId: (_0 = (_z = data.statusPage) === null || _z === void 0 ? void 0 : _z.id) === null || _0 === void 0 ? void 0 : _0.toString(),
1034
1787
  });
1035
1788
  let shouldSendNotificationForEventType = false;
1036
1789
  if (subscriberEventTypes.includes(data.eventType)) {
1037
1790
  logger.debug("Event type matches subscriber's event type.", {
1038
- statusPageId: (_1 = (_0 = data.statusPage) === null || _0 === void 0 ? void 0 : _0.id) === null || _1 === void 0 ? void 0 : _1.toString(),
1791
+ statusPageId: (_2 = (_1 = data.statusPage) === null || _1 === void 0 ? void 0 : _1.id) === null || _2 === void 0 ? void 0 : _2.toString(),
1039
1792
  });
1040
1793
  shouldSendNotificationForEventType = true;
1041
1794
  }
@@ -1110,6 +1863,13 @@ Stay informed about service availability! 🚀`;
1110
1863
  * every episode notification from being sent.
1111
1864
  */
1112
1865
  showEpisodesOnStatusPage: true,
1866
+ /*
1867
+ * IncidentStatusPageScope decides from this which incidents reach a
1868
+ * page, and treats a page without it as showing only incidents
1869
+ * limited to it - so leaving it out would silence every unscoped
1870
+ * incident's notifications.
1871
+ */
1872
+ onlyShowScopedIncidents: true,
1113
1873
  },
1114
1874
  });
1115
1875
  logger.debug("Found status pages:", {});
@@ -1226,12 +1986,60 @@ You will receive real-time notifications for:
1226
1986
  }
1227
1987
  }
1228
1988
  }
1989
+ __decorate([
1990
+ CaptureSpan(),
1991
+ __metadata("design:type", Function),
1992
+ __metadata("design:paramtypes", [Object]),
1993
+ __metadata("design:returntype", Promise)
1994
+ ], Service.prototype, "create", null);
1995
+ __decorate([
1996
+ CaptureSpan(),
1997
+ __metadata("design:type", Function),
1998
+ __metadata("design:paramtypes", [Model]),
1999
+ __metadata("design:returntype", Promise)
2000
+ ], Service.prototype, "createFromStatusPageSignUp", null);
1229
2001
  __decorate([
1230
2002
  CaptureSpan(),
1231
2003
  __metadata("design:type", Function),
1232
2004
  __metadata("design:paramtypes", [Object]),
1233
2005
  __metadata("design:returntype", Promise)
1234
2006
  ], Service.prototype, "onBeforeCreate", null);
2007
+ __decorate([
2008
+ CaptureSpan(),
2009
+ __metadata("design:type", Function),
2010
+ __metadata("design:paramtypes", [Object]),
2011
+ __metadata("design:returntype", Promise)
2012
+ ], Service.prototype, "onBeforeUpdate", null);
2013
+ __decorate([
2014
+ CaptureSpan(),
2015
+ __metadata("design:type", Function),
2016
+ __metadata("design:paramtypes", [Object, Array]),
2017
+ __metadata("design:returntype", Promise)
2018
+ ], Service.prototype, "onUpdateSuccess", null);
2019
+ __decorate([
2020
+ CaptureSpan(),
2021
+ __metadata("design:type", Function),
2022
+ __metadata("design:paramtypes", [Object]),
2023
+ __metadata("design:returntype", Promise)
2024
+ ], Service.prototype, "unsubscribe", null);
2025
+ __decorate([
2026
+ CaptureSpan(),
2027
+ __metadata("design:type", Function),
2028
+ __metadata("design:paramtypes", [Object]),
2029
+ __metadata("design:returntype", Promise)
2030
+ ], Service.prototype, "getUnsubscribeLinkDetails", null);
2031
+ __decorate([
2032
+ CaptureSpan(),
2033
+ __metadata("design:type", Function),
2034
+ __metadata("design:paramtypes", [Object]),
2035
+ __metadata("design:returntype", Promise)
2036
+ ], Service.prototype, "unsubscribeWithLink", null);
2037
+ __decorate([
2038
+ CaptureSpan(),
2039
+ __metadata("design:type", Function),
2040
+ __metadata("design:paramtypes", [Object]),
2041
+ __metadata("design:returntype", Promise)
2042
+ ], Service.prototype, "notifyTeamOfUnsubscribe", null);
1235
2043
  __decorate([
1236
2044
  CaptureSpan(),
1237
2045
  __metadata("design:type", Function),
@@ -1253,9 +2061,27 @@ __decorate([
1253
2061
  __decorate([
1254
2062
  CaptureSpan(),
1255
2063
  __metadata("design:type", Function),
1256
- __metadata("design:paramtypes", [ObjectID, Object]),
2064
+ __metadata("design:paramtypes", [ObjectID, Object, Object]),
1257
2065
  __metadata("design:returntype", Promise)
1258
2066
  ], Service.prototype, "getSubscribersByStatusPage", null);
2067
+ __decorate([
2068
+ CaptureSpan(),
2069
+ __metadata("design:type", Function),
2070
+ __metadata("design:paramtypes", [Object]),
2071
+ __metadata("design:returntype", Promise)
2072
+ ], Service.prototype, "countActiveSubscribersByChannel", null);
2073
+ __decorate([
2074
+ CaptureSpan(),
2075
+ __metadata("design:type", Function),
2076
+ __metadata("design:paramtypes", [Array]),
2077
+ __metadata("design:returntype", Promise)
2078
+ ], Service.prototype, "ensureUnsubscribeTokens", null);
2079
+ __decorate([
2080
+ CaptureSpan(),
2081
+ __metadata("design:type", Function),
2082
+ __metadata("design:paramtypes", [Object]),
2083
+ __metadata("design:returntype", Promise)
2084
+ ], Service.prototype, "backfillUnsubscribeColumns", null);
1259
2085
  __decorate([
1260
2086
  CaptureSpan(),
1261
2087
  __metadata("design:type", Function),