@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
@@ -0,0 +1,322 @@
1
+ import URL from "../API/URL";
2
+ import { JSONObject } from "../JSON";
3
+ import IncidentSubscriberAudience, {
4
+ IncidentSubscriberAudienceCounts,
5
+ IncidentSubscriberAudienceResult,
6
+ } from "./IncidentSubscriberAudience";
7
+ import StatusPageSubscriberUnsubscribe from "./StatusPageSubscriberUnsubscribe";
8
+
9
+ /*
10
+ * "Preview notification" and "Send test to me": the email a status page's
11
+ * subscribers would get about an incident, shown before anything is sent -
12
+ * on the last step of declaring an incident, and while a public note is being
13
+ * written.
14
+ *
15
+ * The server (App/FeatureSet/Notification/API/SubscriberNotificationPreview)
16
+ * builds each page's email through SubscriberIncidentEmailBuilder, the one
17
+ * code path the subscriber jobs send through, and renders it with the mailer's
18
+ * own MailService.render. So the subject and HTML shown here are the ones a
19
+ * subscriber gets, apart from one thing: every subscriber's unsubscribe link
20
+ * carries their own token, which a preview has no subscriber to take it from,
21
+ * so the preview's link is a sample (getPreviewUnsubscribeUrl).
22
+ *
23
+ * Only counts ever leave the server: no subscriber address is read out.
24
+ *
25
+ * Everything here is shared by the server, which answers, and the dashboard,
26
+ * which asks and shows, so the two cannot drift apart.
27
+ */
28
+
29
+ // Which email is previewed.
30
+ export enum SubscriberNotificationPreviewEvent {
31
+ // "Incident created", for an incident that is being declared.
32
+ IncidentCreated = "IncidentCreated",
33
+ // "Incident update", for a public note being written on an incident.
34
+ IncidentPublicNoteCreated = "IncidentPublicNoteCreated",
35
+ }
36
+
37
+ /*
38
+ * Why a status page's subscribers get the email they get. The jobs use the
39
+ * page's custom email template only when it has a body and the page sends
40
+ * through its own SMTP server; everything else gets the default email.
41
+ */
42
+ export enum SubscriberEmailTemplateChoiceReason {
43
+ // The page's custom template, sent through the page's own SMTP server.
44
+ CustomTemplate = "CustomTemplate",
45
+ // No custom email template is linked to the page for this event.
46
+ NoCustomTemplate = "NoCustomTemplate",
47
+ // A custom template is linked, but the page has no SMTP server of its own.
48
+ CustomTemplateNeedsCustomSmtp = "CustomTemplateNeedsCustomSmtp",
49
+ // A custom template is linked, but its body is empty.
50
+ CustomTemplateIsEmpty = "CustomTemplateIsEmpty",
51
+ }
52
+
53
+ export interface SubscriberEmailTemplateChoice {
54
+ usesCustomTemplate: boolean;
55
+ reason: SubscriberEmailTemplateChoiceReason;
56
+ // The linked custom template's name, when there is one (used or not).
57
+ customTemplateName?: string | undefined;
58
+ }
59
+
60
+ // Why nothing will be sent, whatever the email would look like.
61
+ export enum SubscriberNotificationPreviewNothingSentReason {
62
+ // No monitor: subscribers hear about an incident through its monitors.
63
+ NoMonitors = "NoMonitors",
64
+ // The incident exists and is hidden from status pages (or private).
65
+ HiddenFromStatusPages = "HiddenFromStatusPages",
66
+ // The incident being declared is private.
67
+ PrivateIncident = "PrivateIncident",
68
+ // 'Notify Status Page Subscribers' is off on the incident being declared.
69
+ NotifyOff = "NotifyOff",
70
+ // No status page that lists its monitors will show it.
71
+ NoStatusPages = "NoStatusPages",
72
+ }
73
+
74
+ // One status page's email, as its subscribers would get it.
75
+ export interface SubscriberNotificationPreviewStatusPage {
76
+ statusPageId: string;
77
+ name: string;
78
+ // The audience summary's "up to" counts, per channel (IncidentSubscriberAudience).
79
+ subscriberCounts: IncidentSubscriberAudienceCounts;
80
+ subject: string;
81
+ html: string;
82
+ templateChoice: SubscriberEmailTemplateChoice;
83
+ }
84
+
85
+ export interface SubscriberNotificationPreviewResult {
86
+ event: SubscriberNotificationPreviewEvent;
87
+ /*
88
+ * Set when nothing will be sent at all; there are no emails to show then.
89
+ * Null when at least one status page will be sent the email.
90
+ */
91
+ nothingSentReason: SubscriberNotificationPreviewNothingSentReason | null;
92
+ /*
93
+ * The pages that will be sent the email that the caller can see, in name
94
+ * order. A page the caller cannot read is neither named nor previewed: it
95
+ * is counted in audience.hiddenStatusPageCount.
96
+ */
97
+ statusPages: Array<SubscriberNotificationPreviewStatusPage>;
98
+ // Who will be told, as the "Will notify" summary shows it.
99
+ audience: IncidentSubscriberAudienceResult;
100
+ }
101
+
102
+ /*
103
+ * The fields of the Declare Incident form that reach the 'incident created'
104
+ * email. The email shows no state, so the state is not asked for.
105
+ */
106
+ export interface SubscriberNotificationPreviewIncidentDraft {
107
+ title: string;
108
+ description: string;
109
+ incidentSeverityId: string | null;
110
+ monitorIds: Array<string>;
111
+ statusPageIds: Array<string>;
112
+ labelIds: Array<string>;
113
+ // The custom field values, by field name, as the incident would store them.
114
+ customFields: JSONObject;
115
+ isPrivate: boolean;
116
+ shouldStatusPageSubscribersBeNotifiedOnIncidentCreated: boolean;
117
+ }
118
+
119
+ export type SubscriberNotificationPreviewRequest =
120
+ | {
121
+ event: SubscriberNotificationPreviewEvent.IncidentCreated;
122
+ incident: SubscriberNotificationPreviewIncidentDraft;
123
+ }
124
+ | {
125
+ event: SubscriberNotificationPreviewEvent.IncidentPublicNoteCreated;
126
+ incidentId: string;
127
+ // The note being written, as Markdown.
128
+ note: string;
129
+ // When the note will say it was posted; null means now.
130
+ postedAt: Date | null;
131
+ };
132
+
133
+ // "Send test to me": one page's email, sent to the caller's own address.
134
+ export type SubscriberNotificationSendTestRequest =
135
+ SubscriberNotificationPreviewRequest & {
136
+ statusPageId: string;
137
+ };
138
+
139
+ export interface SubscriberNotificationSendTestResult {
140
+ // The caller's own account email, where the test went.
141
+ sentTo: string;
142
+ }
143
+
144
+ export default class SubscriberNotificationPreview {
145
+ // Where the router is mounted, under the notification API.
146
+ public static readonly routerPath: string =
147
+ "/subscriber-notification-preview";
148
+
149
+ public static readonly previewPath: string = "/preview";
150
+
151
+ public static readonly sendTestPath: string = "/send-test";
152
+
153
+ // The longest note or description a preview takes.
154
+ public static readonly maxTextLength: number = 100000;
155
+
156
+ // The longest title a preview takes.
157
+ public static readonly maxTitleLength: number = 1000;
158
+
159
+ /*
160
+ * The most custom field values an incident being previewed carries, and
161
+ * how long they may be together, written out as JSON. Each value is
162
+ * rendered, Markdown included, and goes into every page's email, so
163
+ * without a bound one request could make the server render as much as it
164
+ * can be sent. A project's own fields fit many times over.
165
+ */
166
+ public static readonly maxCustomFieldCount: number = 250;
167
+
168
+ public static readonly maxCustomFieldsLength: number = 200000;
169
+
170
+ // What a test email's subject starts with, so it reads as a test.
171
+ public static readonly testEmailSubjectPrefix: string = "[Test] ";
172
+
173
+ /*
174
+ * The unsubscribe link a preview and a test email carry. A subscriber's
175
+ * real link carries its own token (StatusPageSubscriberUnsubscribe), which
176
+ * a preview has no subscriber for, so this one names no subscription: the
177
+ * status page opens it as an out-of-date link and changes nothing.
178
+ */
179
+ public static getPreviewUnsubscribeUrl(statusPageUrl: string): string {
180
+ return URL.fromString(statusPageUrl)
181
+ .addRoute(
182
+ `/${StatusPageSubscriberUnsubscribe.PAGE_ROUTE_SEGMENT}/preview`,
183
+ )
184
+ .toString();
185
+ }
186
+
187
+ public static toJSON(
188
+ result: SubscriberNotificationPreviewResult,
189
+ ): JSONObject {
190
+ return {
191
+ event: result.event,
192
+ nothingSentReason: result.nothingSentReason,
193
+ statusPages: result.statusPages.map(
194
+ (statusPage: SubscriberNotificationPreviewStatusPage): JSONObject => {
195
+ return {
196
+ statusPageId: statusPage.statusPageId,
197
+ name: statusPage.name,
198
+ subscriberCounts: { ...statusPage.subscriberCounts },
199
+ subject: statusPage.subject,
200
+ html: statusPage.html,
201
+ templateChoice: {
202
+ usesCustomTemplate: statusPage.templateChoice.usesCustomTemplate,
203
+ reason: statusPage.templateChoice.reason,
204
+ customTemplateName:
205
+ statusPage.templateChoice.customTemplateName || null,
206
+ },
207
+ };
208
+ },
209
+ ),
210
+ audience: IncidentSubscriberAudience.toJSON(result.audience),
211
+ };
212
+ }
213
+
214
+ /*
215
+ * The server's answer as the dashboard receives it. Read defensively: a
216
+ * field that is missing or of the wrong type reads as "nothing", so a
217
+ * preview can never break the form it opens from.
218
+ */
219
+ public static fromJSON(
220
+ json: JSONObject,
221
+ ): SubscriberNotificationPreviewResult {
222
+ const events: Array<string> = Object.values(
223
+ SubscriberNotificationPreviewEvent,
224
+ );
225
+ const reasons: Array<string> = Object.values(
226
+ SubscriberNotificationPreviewNothingSentReason,
227
+ );
228
+ const choiceReasons: Array<string> = Object.values(
229
+ SubscriberEmailTemplateChoiceReason,
230
+ );
231
+
232
+ const statusPagesJson: Array<JSONObject> = Array.isArray(
233
+ json["statusPages"],
234
+ )
235
+ ? ((json["statusPages"] as Array<unknown>).filter(
236
+ (item: unknown): boolean => {
237
+ return Boolean(item) && typeof item === "object";
238
+ },
239
+ ) as Array<JSONObject>)
240
+ : [];
241
+
242
+ return {
243
+ event: events.includes(String(json["event"]))
244
+ ? (json["event"] as SubscriberNotificationPreviewEvent)
245
+ : SubscriberNotificationPreviewEvent.IncidentCreated,
246
+ nothingSentReason: reasons.includes(String(json["nothingSentReason"]))
247
+ ? (json[
248
+ "nothingSentReason"
249
+ ] as SubscriberNotificationPreviewNothingSentReason)
250
+ : null,
251
+ statusPages: statusPagesJson.map(
252
+ (item: JSONObject): SubscriberNotificationPreviewStatusPage => {
253
+ const choice: JSONObject =
254
+ (item["templateChoice"] as JSONObject | undefined) || {};
255
+
256
+ return {
257
+ statusPageId: String(item["statusPageId"] || ""),
258
+ name: String(item["name"] || ""),
259
+ subscriberCounts: IncidentSubscriberAudience.countsFromJSON(
260
+ item["subscriberCounts"],
261
+ ),
262
+ subject: String(item["subject"] || ""),
263
+ html: String(item["html"] || ""),
264
+ templateChoice: {
265
+ usesCustomTemplate: choice["usesCustomTemplate"] === true,
266
+ reason: choiceReasons.includes(String(choice["reason"]))
267
+ ? (choice["reason"] as SubscriberEmailTemplateChoiceReason)
268
+ : SubscriberEmailTemplateChoiceReason.NoCustomTemplate,
269
+ customTemplateName:
270
+ typeof choice["customTemplateName"] === "string" &&
271
+ choice["customTemplateName"]
272
+ ? choice["customTemplateName"]
273
+ : undefined,
274
+ },
275
+ };
276
+ },
277
+ ),
278
+ audience: IncidentSubscriberAudience.fromJSON(
279
+ (json["audience"] as JSONObject | undefined) || {},
280
+ ),
281
+ };
282
+ }
283
+
284
+ // A request as it travels: the dates as ISO strings.
285
+ public static requestToJSON(
286
+ request:
287
+ | SubscriberNotificationPreviewRequest
288
+ | SubscriberNotificationSendTestRequest,
289
+ ): JSONObject {
290
+ const json: JSONObject = {
291
+ event: request.event,
292
+ };
293
+
294
+ if (request.event === SubscriberNotificationPreviewEvent.IncidentCreated) {
295
+ json["incident"] = {
296
+ title: request.incident.title,
297
+ description: request.incident.description,
298
+ incidentSeverityId: request.incident.incidentSeverityId,
299
+ monitorIds: [...request.incident.monitorIds],
300
+ statusPageIds: [...request.incident.statusPageIds],
301
+ labelIds: [...request.incident.labelIds],
302
+ customFields: { ...request.incident.customFields },
303
+ isPrivate: request.incident.isPrivate,
304
+ shouldStatusPageSubscribersBeNotifiedOnIncidentCreated:
305
+ request.incident
306
+ .shouldStatusPageSubscribersBeNotifiedOnIncidentCreated,
307
+ };
308
+ } else {
309
+ json["incidentId"] = request.incidentId;
310
+ json["note"] = request.note;
311
+ json["postedAt"] = request.postedAt
312
+ ? request.postedAt.toISOString()
313
+ : null;
314
+ }
315
+
316
+ if ("statusPageId" in request && request.statusPageId) {
317
+ json["statusPageId"] = request.statusPageId;
318
+ }
319
+
320
+ return json;
321
+ }
322
+ }
@@ -0,0 +1,132 @@
1
+ import StatusPageSubscriberNotificationStatus from "./StatusPageSubscriberNotificationStatus";
2
+
3
+ /*
4
+ * Sending a status page subscriber notification again: an incident public
5
+ * note's, or the notification that an incident was created.
6
+ *
7
+ * A notification is sent again by putting its status back to Pending; the
8
+ * job that sends it picks up Pending rows. What that reaches differs:
9
+ *
10
+ * - a public note (and a state change) is sent to every status page the
11
+ * incident reaches now, including the pages that were sent it before;
12
+ * - the incident-created notification keeps a record of the pages it was
13
+ * sent to in full (Incident.statusPagesNotifiedOnCreation). Retry after a
14
+ * failure resumes after them; Resend after a success, and 'Resend to all
15
+ * pages' after a failure (IncidentCreatedResend), empty the record so every
16
+ * page is sent it again.
17
+ *
18
+ * Which of the two a settled notification offers is decided here, so the
19
+ * dashboard's buttons and the server's checks cannot drift apart:
20
+ *
21
+ * - Success offers Resend: it went out, and someone wants it to go out again
22
+ * (a list that was fixed, a page added after a scope change);
23
+ * - Failed offers Retry: not everyone was sent it;
24
+ * - Skipped offers nothing. A note posted with notify off keeps
25
+ * shouldStatusPageSubscribersBeNotifiedOnNoteCreated false - a column no
26
+ * one may update - and the job only sends notes with it true, so a skipped
27
+ * note put back to Pending would sit there forever. Other skips (a hidden
28
+ * incident, no monitors) would only be skipped again; publishing a hidden
29
+ * incident offers its own 'notify' checkbox (IncidentCreatedRenotify);
30
+ * - Pending and InProgress offer nothing: the notification is on its way.
31
+ */
32
+ export enum SubscriberNotificationResendAction {
33
+ // After a failure: send it again to whoever was not sent it.
34
+ Retry = "Retry",
35
+ // After a success: send it again to everyone it reaches now.
36
+ Resend = "Resend",
37
+ }
38
+
39
+ export default class SubscriberNotificationResend {
40
+ /*
41
+ * Why the server refuses to send a public note's notification again,
42
+ * shown to whoever asked.
43
+ */
44
+ public static readonly notePostedWithoutNotifyingMessage: string =
45
+ "This note was posted without notifying subscribers, so there is nothing to resend. Post a new note with Notify Status Page Subscribers ticked to tell them.";
46
+
47
+ public static readonly beingSentMessage: string =
48
+ "This notification is being sent right now. Wait until it has finished, then send it again.";
49
+
50
+ public static readonly noPermissionToResendNoteMessage: string =
51
+ "You do not have permission to send this note's notification again. Sending it again needs the permission to post public notes that notify subscribers, as well as the permission to edit public notes.";
52
+
53
+ public static readonly noPermissionToNotifyAboutEditMessage: string =
54
+ "You do not have permission to notify subscribers about this edit. Notifying them needs the permission to post public notes that notify subscribers, as well as the permission to edit public notes. Save the edit without notifying subscribers, or ask someone who can post notifying notes.";
55
+
56
+ public static readonly updateBeingSentMessage: string =
57
+ "This note's update notification is being sent right now. Wait until it has finished, then save your edit with Notify subscribers about this update ticked again - or save it without notifying subscribers.";
58
+
59
+ /*
60
+ * What a notification in `status` offers: Retry after a failure, and
61
+ * Resend after a success where the caller supports resending one
62
+ * (`isResendAfterSuccessOffered`). Null for anything else.
63
+ *
64
+ * A caller that leaves `isResendAfterSuccessOffered` off keeps the old
65
+ * behaviour: only a failed notification can be sent again.
66
+ */
67
+ public static getAction(data: {
68
+ status: StatusPageSubscriberNotificationStatus | undefined | null;
69
+ isResendAfterSuccessOffered: boolean;
70
+ }): SubscriberNotificationResendAction | null {
71
+ if (data.status === StatusPageSubscriberNotificationStatus.Failed) {
72
+ return SubscriberNotificationResendAction.Retry;
73
+ }
74
+
75
+ if (
76
+ data.status === StatusPageSubscriberNotificationStatus.Success &&
77
+ data.isResendAfterSuccessOffered
78
+ ) {
79
+ return SubscriberNotificationResendAction.Resend;
80
+ }
81
+
82
+ return null;
83
+ }
84
+
85
+ /*
86
+ * Why a public note's notification may not be put back to Pending by a
87
+ * user or an API key, or null when it may:
88
+ *
89
+ * - a note posted with notify off: the job never sends it (see the header),
90
+ * so the note would sit in Pending forever;
91
+ * - a notification being sent right now: the send settles its own status
92
+ * when it finishes and would overwrite the Pending, so the request would
93
+ * be lost without a word.
94
+ *
95
+ * Success and Failed are the cases the dashboard offers. Pending is
96
+ * allowed and changes nothing. A skipped notification of a note that does
97
+ * notify (the incident was hidden, or had no monitors, when it went out)
98
+ * is allowed too: the job looks at it afresh, so it goes out if what
99
+ * skipped it has changed. The dashboard does not offer that one.
100
+ */
101
+ public static getPublicNoteResendRefusal(data: {
102
+ status: StatusPageSubscriberNotificationStatus | undefined | null;
103
+ shouldStatusPageSubscribersBeNotifiedOnNoteCreated:
104
+ | boolean
105
+ | undefined
106
+ | null;
107
+ }): string | null {
108
+ if (data.shouldStatusPageSubscribersBeNotifiedOnNoteCreated === false) {
109
+ return this.notePostedWithoutNotifyingMessage;
110
+ }
111
+
112
+ if (data.status === StatusPageSubscriberNotificationStatus.InProgress) {
113
+ return this.beingSentMessage;
114
+ }
115
+
116
+ return null;
117
+ }
118
+
119
+ /*
120
+ * Whether an update asks for a public note's notification to be sent
121
+ * again: it writes Pending into the note's 'posted' status column. The
122
+ * workers write that column too, but as root, which is never checked.
123
+ */
124
+ public static isPublicNoteResendRequested(
125
+ data: { subscriberNotificationStatusOnNoteCreated?: unknown } | undefined,
126
+ ): boolean {
127
+ return (
128
+ data?.subscriberNotificationStatusOnNoteCreated ===
129
+ StatusPageSubscriberNotificationStatus.Pending
130
+ );
131
+ }
132
+ }
@@ -0,0 +1,180 @@
1
+ import SafeHtml from "../SafeHtml";
2
+
3
+ /*
4
+ * Fills the {{variable}} placeholders of a status page's custom subscriber
5
+ * notification templates.
6
+ *
7
+ * There are two ways in, and which one a template takes depends on what its
8
+ * channel renders, never on the variables:
9
+ *
10
+ * - compileEmailBodyTemplate, for the body of an EMAIL template. The body
11
+ * is sent as HTML (it is wrapped only by BlankTemplate), so a value is
12
+ * inserted as written only when it is a SafeHtml: Markdown the note or
13
+ * description was rendered from, the date helper's HTML, the escaped
14
+ * resource list. Every other value is plain text - a title, a severity or
15
+ * state name, a status page name, a URL - and is HTML-escaped first, so a
16
+ * title such as `<a href="https://evil.example">Reset your password</a>`
17
+ * reads as those characters instead of arriving as a live link.
18
+ * - compileTemplate, for everything that is NOT HTML: an email subject,
19
+ * SMS, Slack and Microsoft Teams. Those channels show text as written, so
20
+ * escaping would put "&amp;" in front of the reader. Its variables are
21
+ * strings, so a SafeHtml (HTML) value cannot reach one by mistake.
22
+ *
23
+ * The escaping is the default rather than something each sender remembers to
24
+ * do: a sender that adds a new plain value to its email variables gets it
25
+ * escaped without doing anything. App/Tests/SubscriberEmailBodyCompileCallSites
26
+ * holds every email template body to compileEmailBodyTemplate.
27
+ *
28
+ * The admin who writes the template is trusted, as before: the template's own
29
+ * HTML is sent as written. Only the values put into it are escaped.
30
+ *
31
+ * Kept free of server dependencies so the dashboard can fill placeholders too.
32
+ */
33
+
34
+ export type SubscriberNotificationTextTemplateVariables = Record<
35
+ string,
36
+ string
37
+ >;
38
+
39
+ export type SubscriberNotificationEmailBodyTemplateVariables = Record<
40
+ string,
41
+ string | SafeHtml
42
+ >;
43
+
44
+ type RenderValueFunction = (name: string) => string | null;
45
+
46
+ /*
47
+ * What may sit between the braces of a placeholder: ASCII letters, digits,
48
+ * underscores and dots, and nothing else (`\w` without the `u` flag is ASCII
49
+ * only). Written once so that the fill below and isPlaceholderName, which
50
+ * the custom field template keys are generated against, cannot disagree.
51
+ */
52
+ const PLACEHOLDER_NAME_SOURCE: string = "[\\w.]+";
53
+
54
+ const PLACEHOLDER_NAME_PATTERN: RegExp = new RegExp(
55
+ `^${PLACEHOLDER_NAME_SOURCE}$`,
56
+ );
57
+
58
+ export default class SubscriberNotificationTemplateCompiler {
59
+ /**
60
+ * Whether `{{name}}` is a placeholder these templates fill in. A name with
61
+ * any other character (a hyphen, a space, a non-ASCII letter) is left in
62
+ * the message as written, so anything that hands out variable names -
63
+ * incident custom field keys, for one - has to produce names this accepts.
64
+ */
65
+ public static isPlaceholderName(name: string): boolean {
66
+ return PLACEHOLDER_NAME_PATTERN.test(name);
67
+ }
68
+
69
+ /**
70
+ * The names of the placeholders these templates hold, each once: exactly
71
+ * the ones the compile functions below would fill, spaces inside the
72
+ * braces allowed, so what a template reads can be known before it is
73
+ * saved or sent. Empty templates are skipped.
74
+ */
75
+ public static getPlaceholderNames(
76
+ templates: Array<string | null | undefined>,
77
+ ): Set<string> {
78
+ const names: Set<string> = new Set<string>();
79
+
80
+ for (const template of templates) {
81
+ if (typeof template !== "string" || !template) {
82
+ continue;
83
+ }
84
+
85
+ for (const match of template.matchAll(
86
+ SubscriberNotificationTemplateCompiler.getPlaceholderPattern(),
87
+ )) {
88
+ names.add(match[1]!);
89
+ }
90
+ }
91
+
92
+ return names;
93
+ }
94
+
95
+ /**
96
+ * Compile a template for a channel that does not render HTML: an email
97
+ * subject, SMS, Slack or Microsoft Teams. Each {{variableName}} is replaced
98
+ * with its value exactly as written.
99
+ *
100
+ * Never use this for the body of an email template: see
101
+ * compileEmailBodyTemplate.
102
+ */
103
+ public static compileTemplate(
104
+ template: string,
105
+ variables: SubscriberNotificationTextTemplateVariables,
106
+ ): string {
107
+ return SubscriberNotificationTemplateCompiler.fillPlaceholders(
108
+ template,
109
+ (name: string): string | null => {
110
+ if (!Object.prototype.hasOwnProperty.call(variables, name)) {
111
+ return null;
112
+ }
113
+
114
+ return variables[name] || "";
115
+ },
116
+ );
117
+ }
118
+
119
+ /**
120
+ * Compile the body of an EMAIL template, which is sent as HTML.
121
+ *
122
+ * A SafeHtml value is inserted as it is. Any other value is plain text and
123
+ * is HTML-escaped, so it can neither add markup nor break out of the
124
+ * attribute it is placed in (href="{{detailsUrl}}").
125
+ */
126
+ public static compileEmailBodyTemplate(
127
+ template: string,
128
+ variables: SubscriberNotificationEmailBodyTemplateVariables,
129
+ ): string {
130
+ return SubscriberNotificationTemplateCompiler.fillPlaceholders(
131
+ template,
132
+ (name: string): string | null => {
133
+ if (!Object.prototype.hasOwnProperty.call(variables, name)) {
134
+ return null;
135
+ }
136
+
137
+ const value: string | SafeHtml | undefined = variables[name];
138
+
139
+ if (SafeHtml.isSafeHtml(value)) {
140
+ return value.toHtml();
141
+ }
142
+
143
+ if (value === null || value === undefined) {
144
+ return "";
145
+ }
146
+
147
+ return SafeHtml.escape(String(value));
148
+ },
149
+ );
150
+ }
151
+
152
+ /*
153
+ * One pass over the template, with a replacer function:
154
+ * - A replacement string would give "$&", "$$", "$`" and "$'" special
155
+ * meaning, so a note mentioning "$$5" or a resource named "Store $&" was
156
+ * rewritten on its way to subscribers.
157
+ * - Replacing one variable at a time also expanded placeholders that
158
+ * appeared inside an earlier value, so a note containing
159
+ * "{{unsubscribeUrl}}" came out as a link.
160
+ * A placeholder with no variable is left as written.
161
+ */
162
+ private static fillPlaceholders(
163
+ template: string,
164
+ renderValue: RenderValueFunction,
165
+ ): string {
166
+ return template.replace(
167
+ SubscriberNotificationTemplateCompiler.getPlaceholderPattern(),
168
+ (placeholder: string, name: string): string => {
169
+ const rendered: string | null = renderValue(name);
170
+
171
+ return rendered === null ? placeholder : rendered;
172
+ },
173
+ );
174
+ }
175
+
176
+ // A fresh global pattern each time: a shared one would carry lastIndex.
177
+ private static getPlaceholderPattern(): RegExp {
178
+ return new RegExp(`{{\\s*(${PLACEHOLDER_NAME_SOURCE})\\s*}}`, "g");
179
+ }
180
+ }