@oneuptime/common 14.0.6 → 14.0.8

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 (556) 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/InventoryItem.ts +23 -12
  6. package/Models/DatabaseModels/StatusPage.ts +55 -0
  7. package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
  8. package/Server/API/IncidentAPI.ts +162 -0
  9. package/Server/API/StatusPageAPI.ts +487 -171
  10. package/Server/API/StatusPageSubscriberAPI.ts +63 -15
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.ts +217 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
  20. package/Server/Infrastructure/Semaphore.ts +10 -0
  21. package/Server/Middleware/IdentityRateLimit.ts +108 -3
  22. package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
  23. package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
  24. package/Server/Services/AlertService.ts +32 -36
  25. package/Server/Services/DatabaseService.ts +93 -10
  26. package/Server/Services/IncidentAlertService.ts +609 -2
  27. package/Server/Services/IncidentCustomFieldService.ts +276 -1
  28. package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
  29. package/Server/Services/IncidentEpisodeService.ts +15 -0
  30. package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
  31. package/Server/Services/IncidentPublicNoteService.ts +30 -1
  32. package/Server/Services/IncidentService.ts +1663 -103
  33. package/Server/Services/IncidentStateTimelineService.ts +13 -0
  34. package/Server/Services/IncidentTemplateService.ts +109 -0
  35. package/Server/Services/InventoryItemService.ts +38 -0
  36. package/Server/Services/IoTDeviceCredentialService.ts +13 -4
  37. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
  38. package/Server/Services/ScheduledMaintenanceService.ts +118 -64
  39. package/Server/Services/SmsService.ts +10 -0
  40. package/Server/Services/StatusPageService.ts +65 -8
  41. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
  42. package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
  43. package/Server/Services/StatusPageSubscriberService.ts +1161 -64
  44. package/Server/Services/UserNotificationRuleService.ts +55 -53
  45. package/Server/Services/WorkspaceNotificationSummaryService.ts +38 -20
  46. package/Server/Types/Markdown.ts +153 -6
  47. package/Server/Types/Workflow/Components/Email.ts +61 -2
  48. package/Server/Utils/AffectedResources/LinkedAffectedResources.ts +576 -0
  49. package/Server/Utils/Alert/AlertStateChangeAuthorization.ts +129 -0
  50. package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
  51. package/Server/Utils/DataSource/EgressGuard.ts +66 -21
  52. package/Server/Utils/Inventory/InventoryOverviewAggregation.ts +111 -0
  53. package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
  54. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
  55. package/Server/Utils/Response.ts +31 -0
  56. package/Server/Utils/SSRFProtection.ts +76 -16
  57. package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
  58. package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
  59. package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
  60. package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
  61. package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
  62. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
  63. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
  64. package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
  65. package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
  66. package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
  67. package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
  68. package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
  69. package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
  70. package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
  71. package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
  72. package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
  73. package/Server/Utils/StatusPageResource.ts +51 -20
  74. package/Server/Utils/Topology/TopologyConcurrencyLimiter.ts +229 -0
  75. package/Server/Utils/Topology/TopologyQueries.ts +1350 -0
  76. package/Server/Utils/Topology/TopologyRequest.ts +463 -0
  77. package/Server/Utils/Topology/TopologyResponseCache.ts +183 -0
  78. package/Server/Utils/Topology/TopologySql.ts +1024 -0
  79. package/Server/Utils/VM/VMAPI.ts +1 -0
  80. package/Server/Utils/VM/VMRunner.ts +10 -0
  81. package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
  82. package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
  83. package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
  84. package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
  85. package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
  86. package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
  87. package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
  88. package/Tests/App/Dashboard/AcknowledgeAlertsOnDeclare.test.ts +369 -0
  89. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +1 -1
  90. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +510 -123
  91. package/Tests/App/Dashboard/AlertsTableAffectedResources.test.tsx +490 -0
  92. package/Tests/App/Dashboard/ChangeAlertStateDeclareIncident.test.tsx +886 -0
  93. package/Tests/App/Dashboard/CreateReviewStepRoleSummary.test.tsx +1250 -0
  94. package/Tests/App/Dashboard/CreateReviewStepSelectionSummary.test.tsx +738 -0
  95. package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
  96. package/Tests/App/Dashboard/DeclareIncidentFromAlert.test.ts +417 -0
  97. package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +1948 -229
  98. package/Tests/App/Dashboard/EntityDetailPanelLifecycle.test.tsx +493 -0
  99. package/Tests/App/Dashboard/EntityDetailPanelNavigation.test.tsx +439 -0
  100. package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
  101. package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
  102. package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
  103. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +534 -6
  104. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +798 -2
  105. package/Tests/App/Dashboard/FetchStateAndSeverityElements.test.tsx +669 -0
  106. package/Tests/App/Dashboard/FetchUsers.test.tsx +230 -0
  107. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
  108. package/Tests/App/Dashboard/IncidentCreateAcknowledgeAlerts.test.tsx +1611 -0
  109. package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
  110. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
  111. package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
  112. package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
  113. package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
  114. package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
  115. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
  116. package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
  117. package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
  118. package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
  119. package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
  120. package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +1365 -57
  121. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +964 -23
  122. package/Tests/App/Dashboard/InventoryRelationships.test.tsx +885 -0
  123. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
  124. package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +201 -15
  125. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +508 -36
  126. package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
  127. package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
  128. package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
  129. package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
  130. package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
  131. package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
  132. package/Tests/App/Dashboard/TopologyDataLifecycle.test.tsx +583 -0
  133. package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +982 -218
  134. package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +818 -114
  135. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
  136. package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
  137. package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
  138. package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
  139. package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
  140. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
  141. package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
  142. package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
  143. package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
  144. package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
  145. package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
  146. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
  147. package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
  148. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
  149. package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
  150. package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
  151. package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
  152. package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
  153. package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +90 -21
  154. package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
  155. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
  156. package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
  157. package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
  158. package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
  159. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
  160. package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
  161. package/Tests/Server/Services/DomainService.test.ts +525 -0
  162. package/Tests/Server/Services/IncidentAlertAcknowledgeOnDeclare.test.ts +2630 -0
  163. package/Tests/Server/Services/IncidentAlertPostgres.test.ts +1625 -1
  164. package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
  165. package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
  166. package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
  167. package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
  168. package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
  169. package/Tests/Server/Services/IncidentDeclareAcknowledgeAlerts.test.ts +2189 -0
  170. package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
  171. package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
  172. package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
  173. package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
  174. package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
  175. package/Tests/Server/Services/InventoryItemServiceOverviewCounts.test.ts +345 -0
  176. package/Tests/Server/Services/InventoryOverviewPostgres.test.ts +254 -0
  177. package/Tests/Server/Services/IoTDeviceCredentialService.test.ts +819 -0
  178. package/Tests/Server/Services/LinkedAffectedResourcesCreatedFeed.test.ts +420 -0
  179. package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
  180. package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
  181. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
  182. package/Tests/Server/Services/SloAffectedResourceCreatedFeed.test.ts +92 -36
  183. package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
  184. package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
  185. package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
  186. package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
  187. package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
  188. package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
  189. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
  190. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
  191. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
  192. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
  193. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
  194. package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
  195. package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
  196. package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
  197. package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
  198. package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
  199. package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
  200. package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
  201. package/Tests/Server/Utils/AffectedResources/LinkedAffectedResources.test.ts +858 -0
  202. package/Tests/Server/Utils/Alert/AlertStateChangeAuthorization.test.ts +1172 -0
  203. package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
  204. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
  205. package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
  206. package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
  207. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
  208. package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
  209. package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
  210. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
  211. package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
  212. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
  213. package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
  214. package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
  215. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
  216. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
  217. package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
  218. package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
  219. package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
  220. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
  221. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
  222. package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
  223. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
  224. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
  225. package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
  226. package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
  227. package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
  228. package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
  229. package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
  230. package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
  231. package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigration.test.ts +386 -0
  232. package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigrationPostgres.test.ts +430 -0
  233. package/Tests/Server/Utils/Topology/TopologyActivityParityPostgres.test.ts +279 -0
  234. package/Tests/Server/Utils/Topology/TopologyConcurrencyLimiter.test.ts +534 -0
  235. package/Tests/Server/Utils/Topology/TopologyEstateGenerator.ts +624 -0
  236. package/Tests/Server/Utils/Topology/TopologyJsonResponse.test.ts +90 -0
  237. package/Tests/Server/Utils/Topology/TopologyQueries.test.ts +1634 -0
  238. package/Tests/Server/Utils/Topology/TopologyQueriesDifferentialPostgres.test.ts +683 -0
  239. package/Tests/Server/Utils/Topology/TopologyQueriesPostgres.test.ts +2624 -0
  240. package/Tests/Server/Utils/Topology/TopologyReference.ts +1018 -0
  241. package/Tests/Server/Utils/Topology/TopologyRequest.test.ts +643 -0
  242. package/Tests/Server/Utils/Topology/TopologyResponseCache.test.ts +305 -0
  243. package/Tests/Server/Utils/Topology/TopologySql.test.ts +973 -0
  244. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
  245. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
  246. package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
  247. package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
  248. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
  249. package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
  250. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
  251. package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
  252. package/Tests/Types/SafeHtml.test.ts +102 -0
  253. package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
  254. package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
  255. package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
  256. package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
  257. package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
  258. package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
  259. package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
  260. package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
  261. package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
  262. package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
  263. package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
  264. package/Tests/Types/Topology/TopologyTypeRules.test.ts +176 -0
  265. package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
  266. package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
  267. package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
  268. package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
  269. package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
  270. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
  271. package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
  272. package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +302 -0
  273. package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
  274. package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
  275. package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
  276. package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
  277. package/Types/CustomField/CustomFieldOrder.ts +55 -0
  278. package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
  279. package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
  280. package/Types/CustomField/CustomFieldType.ts +14 -0
  281. package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
  282. package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
  283. package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
  284. package/Types/Incident/IncidentAlertLink.ts +19 -0
  285. package/Types/SafeHtml.ts +93 -0
  286. package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
  287. package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
  288. package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
  289. package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
  290. package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
  291. package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
  292. package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
  293. package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
  294. package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
  295. package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
  296. package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
  297. package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
  298. package/Types/Telemetry/InventoryLiveness.ts +26 -0
  299. package/Types/Topology/TopologyApi.ts +428 -0
  300. package/Types/Topology/TopologyTypeRules.ts +191 -0
  301. package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
  302. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
  303. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
  304. package/UI/Components/Forms/ModelForm.tsx +70 -8
  305. package/UI/Components/Forms/Validation.ts +1 -1
  306. package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
  307. package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
  308. package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
  309. package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
  310. package/UI/Components/ModelTable/ModelTable.tsx +6 -7
  311. package/UI/Utils/SensitiveUrlToken.ts +10 -5
  312. package/Utils/API.ts +247 -2
  313. package/Utils/Incident/IncidentFromAlerts.ts +78 -0
  314. package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
  315. package/Utils/Markdown/MarkdownEscape.ts +65 -0
  316. package/Utils/ProbeNetworkFailureUtil.ts +673 -0
  317. package/build/dist/Models/DatabaseModels/Incident.js +267 -1
  318. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  319. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
  320. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  321. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
  322. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  323. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
  324. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  325. package/build/dist/Models/DatabaseModels/InventoryItem.js +20 -11
  326. package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
  327. package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
  328. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  329. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
  330. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  331. package/build/dist/Server/API/IncidentAPI.js +100 -1
  332. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  333. package/build/dist/Server/API/StatusPageAPI.js +417 -176
  334. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  335. package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
  336. package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
  337. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js +165 -0
  338. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js.map +1 -0
  339. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
  340. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
  341. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
  342. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
  343. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
  344. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
  345. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
  346. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
  347. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
  348. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
  349. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
  350. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
  351. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
  352. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
  353. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
  354. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  355. package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
  356. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  357. package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
  358. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
  359. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
  360. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
  361. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
  362. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
  363. package/build/dist/Server/Services/AlertService.js +21 -33
  364. package/build/dist/Server/Services/AlertService.js.map +1 -1
  365. package/build/dist/Server/Services/DatabaseService.js +56 -7
  366. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  367. package/build/dist/Server/Services/IncidentAlertService.js +457 -3
  368. package/build/dist/Server/Services/IncidentAlertService.js.map +1 -1
  369. package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
  370. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  371. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
  372. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  373. package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
  374. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  375. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
  376. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  377. package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
  378. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  379. package/build/dist/Server/Services/IncidentService.js +1148 -42
  380. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  381. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  382. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  383. package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
  384. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  385. package/build/dist/Server/Services/InventoryItemService.js +31 -0
  386. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  387. package/build/dist/Server/Services/IoTDeviceCredentialService.js +12 -5
  388. package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -1
  389. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
  390. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  391. package/build/dist/Server/Services/ScheduledMaintenanceService.js +84 -57
  392. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  393. package/build/dist/Server/Services/SmsService.js +2 -22
  394. package/build/dist/Server/Services/SmsService.js.map +1 -1
  395. package/build/dist/Server/Services/StatusPageService.js +47 -9
  396. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  397. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
  398. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  399. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
  400. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
  401. package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
  402. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  403. package/build/dist/Server/Services/UserNotificationRuleService.js +55 -51
  404. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  405. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +42 -25
  406. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
  407. package/build/dist/Server/Types/Markdown.js +110 -6
  408. package/build/dist/Server/Types/Markdown.js.map +1 -1
  409. package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
  410. package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
  411. package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js +405 -0
  412. package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js.map +1 -0
  413. package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js +112 -0
  414. package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js.map +1 -0
  415. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
  416. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
  417. package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
  418. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  419. package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js +81 -0
  420. package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js.map +1 -0
  421. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
  422. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
  423. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
  424. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  425. package/build/dist/Server/Utils/Response.js +30 -0
  426. package/build/dist/Server/Utils/Response.js.map +1 -1
  427. package/build/dist/Server/Utils/SSRFProtection.js +48 -6
  428. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  429. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
  430. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
  431. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
  432. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
  433. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
  434. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
  435. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
  436. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
  437. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
  438. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
  439. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
  440. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
  441. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
  442. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
  443. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
  444. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
  445. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
  446. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
  447. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
  448. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
  449. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
  450. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
  451. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
  452. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
  453. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
  454. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
  455. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
  456. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
  457. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
  458. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
  459. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
  460. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
  461. package/build/dist/Server/Utils/StatusPageResource.js +39 -7
  462. package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
  463. package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js +178 -0
  464. package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js.map +1 -0
  465. package/build/dist/Server/Utils/Topology/TopologyQueries.js +884 -0
  466. package/build/dist/Server/Utils/Topology/TopologyQueries.js.map +1 -0
  467. package/build/dist/Server/Utils/Topology/TopologyRequest.js +275 -0
  468. package/build/dist/Server/Utils/Topology/TopologyRequest.js.map +1 -0
  469. package/build/dist/Server/Utils/Topology/TopologyResponseCache.js +146 -0
  470. package/build/dist/Server/Utils/Topology/TopologyResponseCache.js.map +1 -0
  471. package/build/dist/Server/Utils/Topology/TopologySql.js +688 -0
  472. package/build/dist/Server/Utils/Topology/TopologySql.js.map +1 -0
  473. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  474. package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
  475. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  476. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
  477. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
  478. package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
  479. package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
  480. package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
  481. package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
  482. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
  483. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
  484. package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
  485. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  486. package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
  487. package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
  488. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
  489. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
  490. package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
  491. package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
  492. package/build/dist/Types/Incident/IncidentAlertLink.js +17 -0
  493. package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -1
  494. package/build/dist/Types/SafeHtml.js +84 -0
  495. package/build/dist/Types/SafeHtml.js.map +1 -0
  496. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
  497. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
  498. package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
  499. package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
  500. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
  501. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
  502. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
  503. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
  504. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
  505. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
  506. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
  507. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
  508. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
  509. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
  510. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
  511. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
  512. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
  513. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
  514. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
  515. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
  516. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
  517. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
  518. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
  519. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
  520. package/build/dist/Types/Telemetry/InventoryLiveness.js +23 -0
  521. package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -1
  522. package/build/dist/Types/Topology/TopologyApi.js +55 -0
  523. package/build/dist/Types/Topology/TopologyApi.js.map +1 -0
  524. package/build/dist/Types/Topology/TopologyTypeRules.js +165 -0
  525. package/build/dist/Types/Topology/TopologyTypeRules.js.map +1 -0
  526. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
  527. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
  528. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
  529. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
  530. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
  531. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  532. package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
  533. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  534. package/build/dist/UI/Components/Forms/Validation.js +1 -1
  535. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  536. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  537. package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
  538. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
  539. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  540. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
  541. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  542. package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
  543. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  544. package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
  545. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
  546. package/build/dist/Utils/API.js +177 -1
  547. package/build/dist/Utils/API.js.map +1 -1
  548. package/build/dist/Utils/Incident/IncidentFromAlerts.js +38 -0
  549. package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -1
  550. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
  551. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
  552. package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
  553. package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
  554. package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
  555. package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
  556. package/package.json +1 -1
@@ -34,6 +34,7 @@ import AIIncidentPostmortemRunner from "../Utils/AI/SRE/IncidentPostmortemRunner
34
34
  import InvestigationGrader from "../Utils/AI/SRE/InvestigationGrader";
35
35
  import { IncidentFeedEventType } from "../../Models/DatabaseModels/IncidentFeed";
36
36
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
37
+ import SubscriberNotificationResendAccess from "../Utils/StatusPage/SubscriberNotificationResendAccess";
37
38
  import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
38
39
  import WorkspaceNotificationRuleService from "./WorkspaceNotificationRuleService";
39
40
  import Semaphore, { SemaphoreMutex } from "../Infrastructure/Semaphore";
@@ -748,6 +749,18 @@ ${createdItem.rootCause}`,
748
749
  protected override async onBeforeUpdate(
749
750
  updateBy: UpdateBy<IncidentStateTimeline>,
750
751
  ): Promise<OnUpdate<IncidentStateTimeline>> {
752
+ /*
753
+ * Retry - a user's Pending - over a state change notification that is
754
+ * being sent would let a second run send it alongside, or be overwritten
755
+ * when the send settles (SubscriberNotificationResendAccess).
756
+ */
757
+ await SubscriberNotificationResendAccess.assertNotQueuedWhileBeingSent({
758
+ modelType: IncidentStateTimeline,
759
+ service: this,
760
+ updateBy: updateBy,
761
+ statusColumns: ["subscriberNotificationStatus"],
762
+ });
763
+
751
764
  const incidentIds: Array<ObjectID> =
752
765
  await this.getIncidentIdsForTimelineQuery(updateBy);
753
766
 
@@ -10,6 +10,7 @@ import LabelService from "./LabelService";
10
10
  import MonitorService from "./MonitorService";
11
11
  import MonitorStatusService from "./MonitorStatusService";
12
12
  import OnCallDutyPolicyService from "./OnCallDutyPolicyService";
13
+ import StatusPageService from "./StatusPageService";
13
14
  import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
14
15
  import LIMIT_MAX from "../../Types/Database/LimitMax";
15
16
  import Dictionary from "../../Types/Dictionary";
@@ -28,6 +29,8 @@ import Query from "../Types/Database/Query";
28
29
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
29
30
  import OwnerRuleAssignment from "../Utils/Rules/OwnerRuleAssignment";
30
31
  import QueryDeepPartialEntity from "../../Types/Database/PartialEntity";
32
+ import StatusPageReadAccess from "../Utils/StatusPage/StatusPageReadAccess";
33
+ import IncidentScopeAddedPagesNotification from "../../Types/StatusPage/IncidentScopeAddedPagesNotification";
31
34
 
32
35
  export class Service extends DatabaseService<Model> {
33
36
  public constructor() {
@@ -52,6 +55,12 @@ export class Service extends DatabaseService<Model> {
52
55
  const projectId: ObjectID | undefined =
53
56
  createBy.props.tenantId || createBy.data.projectId;
54
57
 
58
+ // Derived from the list, whatever the caller sent (see the column).
59
+ createBy.data.isScopedToStatusPages =
60
+ IncidentScopeAddedPagesNotification.normalizeStatusPageIds(
61
+ createBy.data.statusPages,
62
+ ).length > 0;
63
+
55
64
  await ProjectScopedReferenceValidator.validateReferencesBelongToProject({
56
65
  projectId: projectId,
57
66
  subject: "incident template",
@@ -64,6 +73,19 @@ export class Service extends DatabaseService<Model> {
64
73
  ],
65
74
  });
66
75
 
76
+ /*
77
+ * A template's status pages are picked for everyone who declares from
78
+ * it, so picking them needs the same read access as picking an
79
+ * incident's (see StatusPageReadAccess).
80
+ */
81
+ await StatusPageReadAccess.assertCallerCanPickStatusPages({
82
+ statusPageIds: IncidentScopeAddedPagesNotification.normalizeStatusPageIds(
83
+ createBy.data.statusPages,
84
+ ),
85
+ props: createBy.props,
86
+ subject: "incident template",
87
+ });
88
+
67
89
  return { createBy, carryForward: null };
68
90
  }
69
91
 
@@ -71,6 +93,22 @@ export class Service extends DatabaseService<Model> {
71
93
  protected override async onBeforeUpdate(
72
94
  updateBy: UpdateBy<Model>,
73
95
  ): Promise<OnUpdate<Model>> {
96
+ /*
97
+ * The scope flag follows a write to the list and nothing else: a client
98
+ * value is dropped, and deleting the template's pages (join rows
99
+ * cascading away) never clears it.
100
+ */
101
+ const data: Dictionary<unknown> = updateBy.data as Dictionary<unknown>;
102
+
103
+ delete data["isScopedToStatusPages"];
104
+
105
+ if (data["statusPages"] !== undefined) {
106
+ data["isScopedToStatusPages"] =
107
+ IncidentScopeAddedPagesNotification.normalizeStatusPageIds(
108
+ data["statusPages"],
109
+ ).length > 0;
110
+ }
111
+
74
112
  const references: Array<ProjectScopedReference> =
75
113
  this.getProjectScopedReferences(updateBy.data);
76
114
 
@@ -131,9 +169,75 @@ export class Service extends DatabaseService<Model> {
131
169
  });
132
170
  }
133
171
 
172
+ // Once the pages are known to be the project's.
173
+ await this.assertCallerCanReadAddedStatusPages(updateBy);
174
+
134
175
  return { updateBy, carryForward: null };
135
176
  }
136
177
 
178
+ /*
179
+ * The status pages an update adds to a template must be pages the caller
180
+ * can read (see StatusPageReadAccess). Pages the template already holds are
181
+ * not checked, so saving a template limited to a page the editor cannot
182
+ * see does not fail. The templates are read as root, limited to the
183
+ * caller's project: the update's own tenant filter is only added after
184
+ * this hook.
185
+ */
186
+ private async assertCallerCanReadAddedStatusPages(
187
+ updateBy: UpdateBy<Model>,
188
+ ): Promise<void> {
189
+ const requested: unknown = (updateBy.data as Dictionary<unknown>)[
190
+ "statusPages"
191
+ ];
192
+
193
+ if (updateBy.props.isRoot || requested === undefined) {
194
+ return;
195
+ }
196
+
197
+ const requestedIds: Array<string> =
198
+ IncidentScopeAddedPagesNotification.normalizeStatusPageIds(requested);
199
+
200
+ if (requestedIds.length === 0) {
201
+ return;
202
+ }
203
+
204
+ const templates: Array<Model> = await this.findBy({
205
+ query: updateBy.props.tenantId
206
+ ? { ...updateBy.query, projectId: updateBy.props.tenantId }
207
+ : updateBy.query,
208
+ select: {
209
+ _id: true,
210
+ statusPages: {
211
+ _id: true,
212
+ },
213
+ },
214
+ limit: LIMIT_MAX,
215
+ skip: 0,
216
+ props: {
217
+ isRoot: true,
218
+ },
219
+ });
220
+
221
+ const addedIds: Array<string> = [];
222
+
223
+ for (const template of templates) {
224
+ for (const id of IncidentScopeAddedPagesNotification.getScopeChange({
225
+ before: template.statusPages,
226
+ after: requestedIds,
227
+ }).addedStatusPageIds) {
228
+ if (!addedIds.includes(id)) {
229
+ addedIds.push(id);
230
+ }
231
+ }
232
+ }
233
+
234
+ await StatusPageReadAccess.assertCallerCanPickStatusPages({
235
+ statusPageIds: addedIds,
236
+ props: updateBy.props,
237
+ subject: "incident template",
238
+ });
239
+ }
240
+
137
241
  /*
138
242
  * The many-to-many lists whose ids must belong to the template's project.
139
243
  * Built per call rather than at module load: these services sit in an
@@ -157,6 +261,11 @@ export class Service extends DatabaseService<Model> {
157
261
  modelName: "On-Call Policy",
158
262
  service: OnCallDutyPolicyService,
159
263
  },
264
+ {
265
+ column: "statusPages",
266
+ modelName: "Status Page",
267
+ service: StatusPageService,
268
+ },
160
269
  ...getAffectedResourceRelations(this.getModel()),
161
270
  ];
162
271
  }
@@ -10,6 +10,8 @@ import ColumnLength from "../../Types/Database/ColumnLength";
10
10
  import QueryDeepPartialEntity from "../../Types/Database/PartialEntity";
11
11
  import CreateBy from "../Types/Database/CreateBy";
12
12
  import { OnCreate } from "../Types/Database/Hooks";
13
+ import { AggregateRow } from "../Types/Database/AggregateBy";
14
+ import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
13
15
  import BadDataException from "../../Types/Exception/BadDataException";
14
16
  import Dictionary from "../../Types/Dictionary";
15
17
  import { JSONObject } from "../../Types/JSON";
@@ -22,6 +24,12 @@ import {
22
24
  MANUAL_ENTITY_IDENTITY_ATTRIBUTE,
23
25
  } from "../../Utils/Telemetry/EntityKey";
24
26
  import logger from "../Utils/Logger";
27
+ import {
28
+ INVENTORY_OVERVIEW_GROUP_BY,
29
+ INVENTORY_OVERVIEW_SELECT,
30
+ InventoryOverviewCounts,
31
+ readInventoryOverviewGroups,
32
+ } from "../Utils/Inventory/InventoryOverviewAggregation";
25
33
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
26
34
  import { ExtractedEntity } from "../Utils/Telemetry/TelemetryEntity";
27
35
  import {
@@ -147,6 +155,36 @@ export class InventoryItemService extends DatabaseService<Model> {
147
155
  return { createBy, carryForward: null };
148
156
  }
149
157
 
158
+ /**
159
+ * The Inventory Overview's tiles and per-type breakdown, counted over the
160
+ * project's whole unarchived estate. See INVENTORY_OVERVIEW_SELECT.
161
+ *
162
+ * Archived rows are excluded because every tile drills into the live Items
163
+ * list, which excludes them too.
164
+ *
165
+ * The GROUP BY carries no limit: capping it would cap the totals summed
166
+ * from it. The number of groups is bounded by the entity-type vocabulary —
167
+ * ingest maps to a fixed set of types, manual creates are confined to
168
+ * MANUAL_ENTITY_TYPES, and the column is not updatable.
169
+ */
170
+ @CaptureSpan()
171
+ public async getOverviewCounts(data: {
172
+ projectId: ObjectID;
173
+ props: DatabaseCommonInteractionProps;
174
+ }): Promise<InventoryOverviewCounts> {
175
+ const rows: Array<AggregateRow> = await this.aggregateBy({
176
+ query: {
177
+ projectId: data.projectId,
178
+ isArchived: false,
179
+ },
180
+ groupBy: INVENTORY_OVERVIEW_GROUP_BY,
181
+ select: INVENTORY_OVERVIEW_SELECT,
182
+ props: data.props,
183
+ });
184
+
185
+ return readInventoryOverviewGroups(rows);
186
+ }
187
+
150
188
  /**
151
189
  * Forward-only registry reconciliation: upsert a catalog row per
152
190
  * discovered entity, bump `lastSeenAt`, merge descriptive attributes
@@ -204,14 +204,23 @@ export class Service extends DatabaseService<Model> {
204
204
  return cached;
205
205
  }
206
206
 
207
- let idObject: ObjectID;
208
- try {
209
- idObject = new ObjectID(credentialId);
210
- } catch {
207
+ /*
208
+ * Validated rather than caught. ObjectID's constructor stores whatever
209
+ * string it is handed and never throws, so the try/catch this replaced
210
+ * caught nothing: a malformed id reached Postgres as an invalid uuid
211
+ * literal, which errors on every attempt AND skipped the negative cache
212
+ * below, because the row was never absent - the query failed. credentialId
213
+ * is an MQTT username, so it is attacker-controlled, and that made the
214
+ * negative cache bypassable with random garbage. Same guard, and the same
215
+ * reason for it, as ProjectAuthorization's API-key check.
216
+ */
217
+ if (!ObjectID.isValidUUID(credentialId)) {
211
218
  this.contextCache.set(credentialId, null, NEGATIVE_TTL_MS);
212
219
  return null;
213
220
  }
214
221
 
222
+ const idObject: ObjectID = new ObjectID(credentialId);
223
+
215
224
  const credential: Model | null = await this.findOneBy({
216
225
  query: { _id: idObject },
217
226
  select: {
@@ -19,6 +19,7 @@ import Query from "../Types/Database/Query";
19
19
  import File from "../../Models/DatabaseModels/File";
20
20
  import FileAttachmentMarkdownUtil from "../Utils/FileAttachmentMarkdownUtil";
21
21
  import { syncIsPublicForMarkdownImages } from "../Utils/InlineImageAccessTokenSync";
22
+ import SubscriberNotificationResendAccess from "../Utils/StatusPage/SubscriberNotificationResendAccess";
22
23
 
23
24
  export class Service extends DatabaseService<Model> {
24
25
  public constructor() {
@@ -122,11 +123,24 @@ export class Service extends DatabaseService<Model> {
122
123
  * An edit tells subscribers nothing unless the editor asked for it on this
123
124
  * edit (see SubscriberUpdateNotification). When they did, queue the update
124
125
  * notification; the ScheduledMaintenancePublicNote worker job sends it.
126
+ *
127
+ * Sending the note's 'posted' notification again - its status written back
128
+ * to Pending, as the dashboard's Retry does - needs the permission to post
129
+ * a note that notifies subscribers, and a note whose notification can go
130
+ * out again (see SubscriberNotificationResendAccess). So does telling
131
+ * subscribers about an edit, which is also refused while that update
132
+ * notification is being sent.
125
133
  */
126
134
  @CaptureSpan()
127
135
  protected override async onBeforeUpdate(
128
136
  updateBy: UpdateBy<Model>,
129
137
  ): Promise<OnUpdate<Model>> {
138
+ await SubscriberNotificationResendAccess.assertPublicNoteResendAllowed({
139
+ modelType: Model,
140
+ service: this,
141
+ updateBy: updateBy,
142
+ });
143
+
130
144
  if (SubscriberUpdateNotification.isRequested(updateBy.miscDataProps)) {
131
145
  updateBy.data.subscriberNotificationStatusOnNoteUpdated =
132
146
  StatusPageSubscriberNotificationStatus.Pending;
@@ -134,6 +148,20 @@ export class Service extends DatabaseService<Model> {
134
148
  SubscriberUpdateNotification.queuedMessage;
135
149
  }
136
150
 
151
+ /*
152
+ * Telling subscribers about the edit - asked for above, or written as
153
+ * Pending directly (the dashboard's Retry of a failed update) - needs
154
+ * the permission to post a note that notifies subscribers too, and is
155
+ * refused while the update notification is being sent.
156
+ */
157
+ await SubscriberNotificationResendAccess.assertPublicNoteUpdateNotificationAllowed(
158
+ {
159
+ modelType: Model,
160
+ service: this,
161
+ updateBy: updateBy,
162
+ },
163
+ );
164
+
137
165
  return {
138
166
  updateBy: updateBy,
139
167
  carryForward: null,
@@ -246,8 +274,9 @@ ${(createdItem.note || "") + attachmentsMarkdown}
246
274
  {
247
275
  scheduledMaintenanceId: updatedItem.scheduledMaintenanceId!,
248
276
  projectId: updatedItem.projectId!,
277
+ // An edit to a public note is a public note event, not a private one.
249
278
  scheduledMaintenanceFeedEventType:
250
- ScheduledMaintenanceFeedEventType.PrivateNote,
279
+ ScheduledMaintenanceFeedEventType.PublicNote,
251
280
  displayColor: Blue500,
252
281
  userId: userId || undefined,
253
282
 
@@ -9,6 +9,10 @@ import DatabaseService from "./DatabaseService";
9
9
  import ScheduledMaintenanceCustomField from "../../Models/DatabaseModels/ScheduledMaintenanceCustomField";
10
10
  import CustomFieldMappingService from "./CustomFieldMappingService";
11
11
  import MonitorService from "./MonitorService";
12
+ import LinkedAffectedResources, {
13
+ LinkedAffectedResource,
14
+ LinkedAffectedResourceRelation,
15
+ } from "../Utils/AffectedResources/LinkedAffectedResources";
12
16
  import ScheduledMaintenanceOwnerTeamService from "./ScheduledMaintenanceOwnerTeamService";
13
17
  import ScheduledMaintenanceOwnerUserService from "./ScheduledMaintenanceOwnerUserService";
14
18
  import ScheduledMaintenanceStateService from "./ScheduledMaintenanceStateService";
@@ -56,6 +60,7 @@ import SmsService from "../../Server/Services/SmsService";
56
60
  import StatusPageResourceService from "../../Server/Services/StatusPageResourceService";
57
61
  import StatusPageService from "../../Server/Services/StatusPageService";
58
62
  import StatusPageSubscriberService from "../../Server/Services/StatusPageSubscriberService";
63
+ import StatusPageSubscriberUnsubscribe from "../../Types/StatusPage/StatusPageSubscriberUnsubscribe";
59
64
  import QueryHelper from "../../Server/Types/Database/QueryHelper";
60
65
  import Markdown, { MarkdownContentType } from "../../Server/Types/Markdown";
61
66
  import logger, { LogAttributes } from "../../Server/Utils/Logger";
@@ -86,6 +91,8 @@ import ProjectService from "./ProjectService";
86
91
  import StatusPageSubscriberNotificationTemplateService, {
87
92
  Service as StatusPageSubscriberNotificationTemplateServiceClass,
88
93
  } from "./StatusPageSubscriberNotificationTemplateService";
94
+ import StatusPageResourceUtil from "../Utils/StatusPageResource";
95
+ import SafeHtml from "../../Types/SafeHtml";
89
96
  import StatusPageSubscriberNotificationTemplate from "../../Models/DatabaseModels/StatusPageSubscriberNotificationTemplate";
90
97
  import StatusPageSubscriberNotificationEventType from "../../Types/StatusPage/StatusPageSubscriberNotificationEventType";
91
98
  import StatusPageSubscriberNotificationMethod from "../../Types/StatusPage/StatusPageSubscriberNotificationMethod";
@@ -204,12 +211,20 @@ export class Service extends DatabaseService<Model> {
204
211
 
205
212
  // Send email to Email subscribers.
206
213
 
214
+ /*
215
+ * The resources are read without their groups, so both forms are the
216
+ * names joined by commas. The HTML one, for email bodies, has every
217
+ * name escaped; SMS, Slack, subjects and webhooks get the names as
218
+ * written.
219
+ */
207
220
  const resourcesAffected: string =
208
- statusPageToResources[statuspage._id!]
209
- ?.map((r: StatusPageResource) => {
210
- return r.displayName;
211
- })
212
- .join(", ") || "";
221
+ StatusPageResourceUtil.getResourcesGroupedByGroupNameAsPlainText(
222
+ statusPageToResources[statuspage._id!] || [],
223
+ );
224
+ const resourcesAffectedHtml: string =
225
+ StatusPageResourceUtil.getResourcesGroupedByGroupName(
226
+ statusPageToResources[statuspage._id!] || [],
227
+ );
213
228
 
214
229
  // Fetch custom templates for each notification method
215
230
  const [
@@ -266,7 +281,7 @@ export class Service extends DatabaseService<Model> {
266
281
  const unsubscribeUrl: string =
267
282
  StatusPageSubscriberService.getUnsubscribeLink(
268
283
  URL.fromString(statusPageURL),
269
- subscriber.id!,
284
+ subscriber,
270
285
  ).toString();
271
286
 
272
287
  // Template variables for custom templates, as Markdown (Slack)
@@ -294,6 +309,19 @@ export class Service extends DatabaseService<Model> {
294
309
  };
295
310
 
296
311
  if (subscriber.subscriberPhone) {
312
+ /*
313
+ * On a public status page the SMS keeps the shorter manage link,
314
+ * which works there without signing in: an SMS is billed by the
315
+ * segment (see StatusPageSubscriberUnsubscribe.buildSmsLink).
316
+ */
317
+ const smsUnsubscribeUrl: string =
318
+ StatusPageSubscriberUnsubscribe.buildSmsLink({
319
+ isPublicStatusPage: statuspage.isPublicStatusPage,
320
+ statusPageUrl: statusPageURL,
321
+ subscriberId: subscriber.id!,
322
+ unsubscribeUrl: unsubscribeUrl,
323
+ });
324
+
297
325
  let smsMessage: string;
298
326
 
299
327
  if (
@@ -305,11 +333,14 @@ export class Service extends DatabaseService<Model> {
305
333
  smsMessage =
306
334
  StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(
307
335
  smsTemplate.templateBody,
308
- plainTextTemplateVariables,
336
+ {
337
+ ...plainTextTemplateVariables,
338
+ unsubscribeUrl: smsUnsubscribeUrl,
339
+ },
309
340
  );
310
341
  } else {
311
342
  // Use default template
312
- smsMessage = `Scheduled Maintenance: ${event.title || ""} on ${statusPageName}.${resourcesAffected ? ` Impact: ${resourcesAffected}.` : ""} Details: ${scheduledEventDetailsUrl}. Unsub: ${unsubscribeUrl}`;
343
+ smsMessage = `Scheduled Maintenance: ${event.title || ""} on ${statusPageName}.${resourcesAffected ? ` Impact: ${resourcesAffected}.` : ""} Details: ${scheduledEventDetailsUrl}. Unsub: ${smsUnsubscribeUrl}`;
313
344
  }
314
345
 
315
346
  const sms: SMS = {
@@ -404,7 +435,20 @@ ${resourcesAffected ? `**Resources Affected:** ${resourcesAffected}` : ""}
404
435
  const statusPageIdString: string | null =
405
436
  statuspage.id?.toString() || statuspage._id?.toString() || null;
406
437
 
407
- // Prepare email variables
438
+ const scheduledAtHtml: string =
439
+ OneUptimeDate.getDateAsFormattedHTMLInMultipleTimezones({
440
+ date: event.startsAt!,
441
+ timezones: statuspage.subscriberTimezones || [],
442
+ use12HourFormat: true,
443
+ });
444
+
445
+ /*
446
+ * The default template's variables. resourcesAffected,
447
+ * scheduledAt and eventDescription are HTML (the template puts
448
+ * them in its raw-HTML slot); the footer is HTML the status
449
+ * page's admins wrote, as they write the template. Everything
450
+ * else is plain text, which the template escapes.
451
+ */
408
452
  const emailVars: Record<string, string> = {
409
453
  statusPageName: statusPageName,
410
454
  statusPageUrl: statusPageURL,
@@ -421,13 +465,8 @@ ${resourcesAffected ? `**Resources Affected:** ${resourcesAffected}` : ""}
421
465
  : "false",
422
466
  subscriberEmailNotificationFooterText:
423
467
  statuspage.subscriberEmailNotificationFooterText || "",
424
- resourcesAffected: resourcesAffected,
425
- scheduledAt:
426
- OneUptimeDate.getDateAsFormattedHTMLInMultipleTimezones({
427
- date: event.startsAt!,
428
- timezones: statuspage.subscriberTimezones || [],
429
- use12HourFormat: true,
430
- }),
468
+ resourcesAffected: resourcesAffectedHtml,
469
+ scheduledAt: scheduledAtHtml,
431
470
  eventTitle: event.title || "",
432
471
  eventDescription: eventDescriptionHtml,
433
472
  unsubscribeUrl: unsubscribeUrl,
@@ -444,14 +483,29 @@ ${resourcesAffected ? `**Resources Affected:** ${resourcesAffected}` : ""}
444
483
  * is configured. The body is HTML, so the description is too.
445
484
  * The subject is plain text, including the email-only
446
485
  * variables that are HTML in the body.
486
+ *
487
+ * In the body, the plain values are escaped
488
+ * (compileEmailBodyTemplate) and only the ones wrapped in
489
+ * SafeHtml below go in as HTML.
447
490
  */
448
491
  const customEmailBody: string =
449
- StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate(
492
+ StatusPageSubscriberNotificationTemplateServiceClass.compileEmailBodyTemplate(
450
493
  emailTemplate.templateBody,
451
494
  {
452
495
  ...templateVariables,
453
496
  ...emailVars,
454
- scheduledMaintenanceDescription: eventDescriptionHtml,
497
+ resourcesAffected: SafeHtml.fromTrustedHtml(
498
+ resourcesAffectedHtml,
499
+ ),
500
+ scheduledAt: SafeHtml.fromTrustedHtml(scheduledAtHtml),
501
+ eventDescription:
502
+ SafeHtml.fromTrustedHtml(eventDescriptionHtml),
503
+ scheduledMaintenanceDescription:
504
+ SafeHtml.fromTrustedHtml(eventDescriptionHtml),
505
+ subscriberEmailNotificationFooterText:
506
+ SafeHtml.fromTrustedHtml(
507
+ emailVars["subscriberEmailNotificationFooterText"],
508
+ ),
455
509
  },
456
510
  );
457
511
  const customEmailSubject: string = emailTemplate.emailSubject
@@ -1180,10 +1234,6 @@ ${resourcesAffected ? `**Resources Affected:** ${resourcesAffected}` : ""}
1180
1234
  },
1181
1235
  startsAt: true,
1182
1236
  endsAt: true,
1183
- monitors: {
1184
- name: true,
1185
- _id: true,
1186
- },
1187
1237
  labels: {
1188
1238
  name: true,
1189
1239
  },
@@ -1448,14 +1498,23 @@ ${scheduledMaintenance.description || "No description provided."}
1448
1498
  feedInfoInMarkdown += `⏳ **Scheduled Maintenance State**: ${scheduledMaintenance.currentScheduledMaintenanceState.name} \n\n`;
1449
1499
  }
1450
1500
 
1451
- if (
1452
- scheduledMaintenance.monitors &&
1453
- scheduledMaintenance.monitors.length > 0
1454
- ) {
1501
+ // Everything the event's Affected Resources card lists, monitors first.
1502
+ const resources: Array<LinkedAffectedResource> =
1503
+ await LinkedAffectedResources.readForScheduledMaintenance({
1504
+ service: this,
1505
+ projectId: scheduledMaintenance.projectId!,
1506
+ scheduledMaintenanceId: scheduledMaintenance.id!,
1507
+ });
1508
+
1509
+ if (resources.length > 0) {
1455
1510
  feedInfoInMarkdown += `🌎 **Resources Affected**:\n`;
1456
1511
 
1457
- for (const monitor of scheduledMaintenance.monitors) {
1458
- feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(scheduledMaintenance.projectId!, monitor.id!)).toString()})\n`;
1512
+ for (const resourceLine of LinkedAffectedResources.getMarkdownLines({
1513
+ dashboardUrl: await DatabaseConfig.getDashboardUrl(),
1514
+ projectId: scheduledMaintenance.projectId!,
1515
+ resources: resources,
1516
+ })) {
1517
+ feedInfoInMarkdown += `${resourceLine}\n`;
1459
1518
  }
1460
1519
 
1461
1520
  feedInfoInMarkdown += `\n\n`;
@@ -1820,47 +1879,42 @@ ${(
1820
1879
  shouldAddScheduledMaintenanceFeed = true;
1821
1880
  }
1822
1881
 
1823
- if (
1824
- onUpdate.updateBy.data.monitors &&
1825
- onUpdate.updateBy.data.monitors.length > 0 &&
1826
- Array.isArray(onUpdate.updateBy.data.monitors)
1827
- ) {
1828
- const monitorIds: Array<ObjectID> = (
1829
- onUpdate.updateBy.data.monitors as any
1830
- )
1831
- .map((monitor: Label) => {
1832
- if (monitor._id) {
1833
- return new ObjectID(monitor._id?.toString());
1834
- }
1882
+ /*
1883
+ * Any affected-resource list in the payload - not only monitors - is
1884
+ * a change to what the event affects. The event is read back rather
1885
+ * than the ids in the payload being looked up: the read is held to
1886
+ * this project, and it names the whole list the card now shows.
1887
+ */
1888
+ const affectedResourcesChanged: boolean =
1889
+ LinkedAffectedResources.getRelations(this.getModel()).some(
1890
+ (relation: LinkedAffectedResourceRelation): boolean => {
1891
+ const value: unknown = (
1892
+ onUpdate.updateBy.data as Record<string, unknown>
1893
+ )[relation.column];
1894
+
1895
+ return Array.isArray(value) && value.length > 0;
1896
+ },
1897
+ );
1835
1898
 
1836
- return null;
1837
- })
1838
- .filter((monitorId: ObjectID | null) => {
1839
- return monitorId !== null;
1840
- });
1899
+ if (affectedResourcesChanged && onUpdate.updateBy.props.tenantId) {
1900
+ const projectId: ObjectID = onUpdate.updateBy.props
1901
+ .tenantId as ObjectID;
1841
1902
 
1842
- const monitors: Array<Label> = await MonitorService.findBy({
1843
- query: {
1844
- _id: QueryHelper.any(monitorIds),
1845
- },
1846
- select: {
1847
- name: true,
1848
- },
1849
- limit: LIMIT_PER_PROJECT,
1850
- skip: 0,
1851
- props: {
1852
- isRoot: true,
1853
- },
1854
- });
1903
+ const resources: Array<LinkedAffectedResource> =
1904
+ await LinkedAffectedResources.readForScheduledMaintenance({
1905
+ service: this,
1906
+ projectId: projectId,
1907
+ scheduledMaintenanceId: scheduledMaintenanceId,
1908
+ });
1855
1909
 
1856
- if (monitors.length > 0) {
1910
+ if (resources.length > 0) {
1857
1911
  feedInfoInMarkdown += `\n\n**Resources Affected**:
1858
1912
 
1859
- ${monitors
1860
- .map((monitor: Monitor) => {
1861
- return `- ${monitor.name}`;
1862
- })
1863
- .join("\n")}
1913
+ ${LinkedAffectedResources.getMarkdownLines({
1914
+ dashboardUrl: await DatabaseConfig.getDashboardUrl(),
1915
+ projectId: projectId,
1916
+ resources: resources,
1917
+ }).join("\n")}
1864
1918
  `;
1865
1919
 
1866
1920
  shouldAddScheduledMaintenanceFeed = true;
@@ -41,6 +41,15 @@ export class SmsService extends BaseService {
41
41
  onCallDutyPolicyExecutionLogTimelineId?: ObjectID | undefined;
42
42
  onCallScheduleId?: ObjectID | undefined;
43
43
  teamId?: ObjectID | undefined;
44
+ /*
45
+ * Answer with an error, not success, when the Notification service
46
+ * deliberately does not send the SMS: the project has SMS notifications
47
+ * turned off, or too little SMS balance. The status page subscriber
48
+ * sends that count what they delivered pass it
49
+ * (SubscriberNotificationDeliveryRecord), so such an SMS counts as
50
+ * failed rather than sent.
51
+ */
52
+ failIfNotSent?: boolean | undefined;
44
53
  },
45
54
  ): Promise<HTTPResponse<EmptyResponseData>> {
46
55
  const body: JSONObject = {
@@ -74,6 +83,7 @@ export class SmsService extends BaseService {
74
83
  options.onCallDutyPolicyExecutionLogTimelineId?.toString(),
75
84
  onCallScheduleId: options.onCallScheduleId?.toString(),
76
85
  teamId: options.teamId?.toString(),
86
+ ...(options.failIfNotSent ? { failIfNotSent: true } : {}),
77
87
  };
78
88
 
79
89
  return await API.post<EmptyResponseData>({