@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,839 @@
1
+ import Incident from "../../../Models/DatabaseModels/Incident";
2
+ import IncidentCustomField from "../../../Models/DatabaseModels/IncidentCustomField";
3
+ import IncidentSeverity from "../../../Models/DatabaseModels/IncidentSeverity";
4
+ import Label from "../../../Models/DatabaseModels/Label";
5
+ import Monitor from "../../../Models/DatabaseModels/Monitor";
6
+ import StatusPage from "../../../Models/DatabaseModels/StatusPage";
7
+ import Hostname from "../../../Types/API/Hostname";
8
+ import Protocol from "../../../Types/API/Protocol";
9
+ import DatabaseCommonInteractionProps from "../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
10
+ import { CustomFieldDefinition } from "../../../Types/CustomField/CustomFieldDefinition";
11
+ import {
12
+ formatCustomFieldValueValidationErrors,
13
+ validateCustomFieldValues,
14
+ } from "../../../Types/CustomField/CustomFieldValueValidator";
15
+ import { LIMIT_PER_PROJECT } from "../../../Types/Database/LimitMax";
16
+ import BadDataException from "../../../Types/Exception/BadDataException";
17
+ import NotFoundException from "../../../Types/Exception/NotFoundException";
18
+ import { JSONObject } from "../../../Types/JSON";
19
+ import ObjectID from "../../../Types/ObjectID";
20
+ import IncidentScopeAddedPagesNotification from "../../../Types/StatusPage/IncidentScopeAddedPagesNotification";
21
+ import IncidentSubscriberAudience, {
22
+ IncidentSubscriberAudienceCounts,
23
+ IncidentSubscriberAudienceResult,
24
+ IncidentSubscriberAudienceStatusPage,
25
+ } from "../../../Types/StatusPage/IncidentSubscriberAudience";
26
+ import SubscriberNotificationPreview, {
27
+ SubscriberEmailTemplateChoice,
28
+ SubscriberNotificationPreviewEvent,
29
+ SubscriberNotificationPreviewIncidentDraft,
30
+ SubscriberNotificationPreviewNothingSentReason,
31
+ SubscriberNotificationPreviewRequest,
32
+ SubscriberNotificationSendTestRequest,
33
+ } from "../../../Types/StatusPage/SubscriberNotificationPreview";
34
+ import DatabaseConfig from "../../DatabaseConfig";
35
+ import CustomFieldMappingService from "../../Services/CustomFieldMappingService";
36
+ import IncidentCustomFieldService from "../../Services/IncidentCustomFieldService";
37
+ import IncidentService from "../../Services/IncidentService";
38
+ import IncidentSeverityService from "../../Services/IncidentSeverityService";
39
+ import LabelService from "../../Services/LabelService";
40
+ import StatusPageService from "../../Services/StatusPageService";
41
+ import QueryHelper from "../../Types/Database/QueryHelper";
42
+ import {
43
+ IncidentStatusPageTemplateVariables,
44
+ IncidentTemplateVariables,
45
+ } from "./IncidentTemplateVariableBuilder";
46
+ import IncidentSubscriberAudienceBuilder, {
47
+ IncidentSubscriberAudienceRequest,
48
+ IncidentSubscriberAudienceWithStatusPages,
49
+ } from "./IncidentSubscriberAudienceBuilder";
50
+ import SubscriberIncidentEmailBuilder, {
51
+ SubscriberIncidentEmail,
52
+ SubscriberIncidentEmailEvent,
53
+ SubscriberIncidentStatusPageEmail,
54
+ } from "./SubscriberIncidentEmailBuilder";
55
+
56
+ /*
57
+ * What "Preview notification" and "Send test to me" show and send: for each
58
+ * status page an incident's email would go to, the email its subscribers
59
+ * would get (see Common/Types/StatusPage/SubscriberNotificationPreview).
60
+ *
61
+ * The emails come from SubscriberIncidentEmailBuilder, the one code path the
62
+ * 'incident created' and public note jobs send through, fed the way those
63
+ * jobs feed it; the router renders them with the mailer's own
64
+ * MailService.render. So what is previewed is what is sent.
65
+ *
66
+ * What the caller learns is bounded exactly as the "Will notify" audience
67
+ * bounds it (IncidentSubscriberAudienceBuilder, which this builds on):
68
+ *
69
+ * - the caller must hold one of the roles that may see the audience;
70
+ * - an incident that exists is read with the caller's own permissions,
71
+ * inside the caller's project, so another project's incident and a
72
+ * private one the caller may not read are "not found";
73
+ * - the monitors, status pages, labels and severity named for an incident
74
+ * being declared must all be the caller's project's;
75
+ * - only the pages the caller may read are previewed or named - in the
76
+ * preview, {{affectedStatusPages}} names only those pages too - and the
77
+ * others are one number (audience.hiddenStatusPageCount). That bound is
78
+ * for looking ahead: once a notification has gone out, its own record
79
+ * names every page it reached to whoever can read the incident (see
80
+ * IncidentSubscriberAudienceBuilder);
81
+ * - subscribers are counted, never read: no address leaves the server.
82
+ *
83
+ * Building a preview has no side effects: nothing is sent, and nothing about
84
+ * the incident - its custom fields' images among them - is changed.
85
+ */
86
+
87
+ // One status page's email, before it is rendered.
88
+ export interface SubscriberNotificationPreviewPage {
89
+ /*
90
+ * The page as the jobs load it, mail settings included: for sending a
91
+ * test through the page's own SMTP server. Never serialized.
92
+ */
93
+ statusPage: StatusPage;
94
+ statusPageId: string;
95
+ // The name the caller knows the page by.
96
+ name: string;
97
+ subscriberCounts: IncidentSubscriberAudienceCounts;
98
+ templateChoice: SubscriberEmailTemplateChoice;
99
+ email: SubscriberIncidentEmail;
100
+ }
101
+
102
+ export interface SubscriberNotificationPreviewBuild {
103
+ event: SubscriberNotificationPreviewEvent;
104
+ nothingSentReason: SubscriberNotificationPreviewNothingSentReason | null;
105
+ audience: IncidentSubscriberAudienceResult;
106
+ statusPages: Array<SubscriberNotificationPreviewPage>;
107
+ }
108
+
109
+ // An incident and what its email needs, once the request is resolved.
110
+ interface PreviewIncident {
111
+ event: SubscriberIncidentEmailEvent;
112
+ incident: Incident;
113
+ note?:
114
+ | {
115
+ text: string;
116
+ postedAt: Date | null;
117
+ }
118
+ | undefined;
119
+ audienceRequest: IncidentSubscriberAudienceRequest;
120
+ // Why nothing will be sent, whatever the audience, for a draft.
121
+ draftNothingSentReason: SubscriberNotificationPreviewNothingSentReason | null;
122
+ }
123
+
124
+ export default class SubscriberNotificationPreviewBuilder {
125
+ /**
126
+ * The emails for a request. With onlyStatusPageId, only that page's email
127
+ * is built (for "Send test to me"); the audience still covers every page.
128
+ */
129
+ public static async build(data: {
130
+ projectId: ObjectID;
131
+ props: DatabaseCommonInteractionProps;
132
+ request: SubscriberNotificationPreviewRequest;
133
+ onlyStatusPageId?: string | undefined;
134
+ }): Promise<SubscriberNotificationPreviewBuild> {
135
+ IncidentSubscriberAudienceBuilder.assertCallerMaySeeAudience(data.props);
136
+
137
+ const previewIncident: PreviewIncident =
138
+ data.request.event === SubscriberNotificationPreviewEvent.IncidentCreated
139
+ ? await this.resolveDraft({
140
+ projectId: data.projectId,
141
+ props: data.props,
142
+ draft: data.request.incident,
143
+ })
144
+ : await this.resolvePublicNote({
145
+ projectId: data.projectId,
146
+ props: data.props,
147
+ incidentId: data.request.incidentId,
148
+ note: data.request.note,
149
+ postedAt: data.request.postedAt,
150
+ });
151
+
152
+ /*
153
+ * Who is told, worked out as the "Will notify" summary works it out -
154
+ * and, for an incident that exists, the read that proves the caller may
155
+ * see it. Nothing about the incident is read before this.
156
+ */
157
+ const withStatusPages: IncidentSubscriberAudienceWithStatusPages =
158
+ await IncidentSubscriberAudienceBuilder.buildWithStatusPages(
159
+ previewIncident.audienceRequest,
160
+ );
161
+ const audience: IncidentSubscriberAudienceResult = withStatusPages.audience;
162
+
163
+ const nothingSentReason: SubscriberNotificationPreviewNothingSentReason | null =
164
+ this.getNothingSentReason({
165
+ audience: audience,
166
+ draftNothingSentReason: previewIncident.draftNothingSentReason,
167
+ });
168
+
169
+ const result: SubscriberNotificationPreviewBuild = {
170
+ event: data.request.event,
171
+ nothingSentReason: nothingSentReason,
172
+ audience: audience,
173
+ statusPages: [],
174
+ };
175
+
176
+ if (nothingSentReason) {
177
+ return result;
178
+ }
179
+
180
+ // The incident's content, now that the caller is known to read it.
181
+ const incident: Incident =
182
+ "incidentId" in previewIncident.audienceRequest
183
+ ? await this.readIncidentContent({
184
+ projectId: data.projectId,
185
+ incidentId: previewIncident.audienceRequest.incidentId,
186
+ })
187
+ : previewIncident.incident;
188
+
189
+ // The pages that will be told that the caller can see, in name order.
190
+ const readableStatusPages: Array<StatusPage> =
191
+ withStatusPages.resolved.statusPages.filter(
192
+ (statusPage: StatusPage): boolean => {
193
+ return Boolean(this.findAudiencePage(audience, statusPage));
194
+ },
195
+ );
196
+
197
+ const statusPagesToBuild: Array<StatusPage> = data.onlyStatusPageId
198
+ ? readableStatusPages.filter((statusPage: StatusPage): boolean => {
199
+ return (
200
+ this.getId(statusPage) === data.onlyStatusPageId!.toLowerCase()
201
+ );
202
+ })
203
+ : readableStatusPages;
204
+
205
+ if (statusPagesToBuild.length === 0) {
206
+ return result;
207
+ }
208
+
209
+ const incidentTemplateVariables: IncidentTemplateVariables =
210
+ await SubscriberIncidentEmailBuilder.buildTemplateVariables({
211
+ event: previewIncident.event,
212
+ incident: incident,
213
+ statusPages: readableStatusPages,
214
+ note: previewIncident.note,
215
+ });
216
+
217
+ const host: Hostname = await DatabaseConfig.getHost();
218
+ const httpProtocol: Protocol = await DatabaseConfig.getHttpProtocol();
219
+
220
+ for (const statusPage of statusPagesToBuild) {
221
+ const audiencePage: IncidentSubscriberAudienceStatusPage =
222
+ this.findAudiencePage(audience, statusPage)!;
223
+
224
+ const statusPageUrl: string = await StatusPageService.getStatusPageURL(
225
+ statusPage.id!,
226
+ );
227
+ const detailsUrl: string = SubscriberIncidentEmailBuilder.getDetailsUrl({
228
+ statusPageUrl: statusPageUrl,
229
+ incidentId: incident.id,
230
+ });
231
+
232
+ const pageTemplateVariables: IncidentStatusPageTemplateVariables =
233
+ incidentTemplateVariables.forStatusPage({
234
+ statusPage: statusPage,
235
+ statusPageUrl: statusPageUrl,
236
+ detailsUrl: detailsUrl,
237
+ resources:
238
+ withStatusPages.resolved.statusPageToResources[statusPage._id!] ||
239
+ [],
240
+ });
241
+
242
+ const pageEmail: SubscriberIncidentStatusPageEmail =
243
+ await SubscriberIncidentEmailBuilder.forStatusPage({
244
+ event: previewIncident.event,
245
+ incident: incident,
246
+ incidentTemplateVariables: incidentTemplateVariables,
247
+ statusPage: statusPage,
248
+ statusPageUrl: statusPageUrl,
249
+ detailsUrl: detailsUrl,
250
+ pageTemplateVariables: pageTemplateVariables,
251
+ host: host,
252
+ httpProtocol: httpProtocol,
253
+ });
254
+
255
+ result.statusPages.push({
256
+ statusPage: statusPage,
257
+ statusPageId: audiencePage.statusPageId,
258
+ name: audiencePage.name,
259
+ subscriberCounts: { ...audiencePage.subscriberCounts },
260
+ templateChoice: pageEmail.templateChoice,
261
+ /*
262
+ * Every subscriber's link carries their own token; a preview has no
263
+ * subscriber, so it carries a link that names none.
264
+ */
265
+ email: pageEmail.forSubscriber({
266
+ unsubscribeUrl:
267
+ SubscriberNotificationPreview.getPreviewUnsubscribeUrl(
268
+ statusPageUrl,
269
+ ),
270
+ }),
271
+ });
272
+ }
273
+
274
+ return result;
275
+ }
276
+
277
+ /*
278
+ * Why nothing will be sent, in the order the jobs find it out: no monitor,
279
+ * an incident hidden from status pages, a draft that will be private or
280
+ * does not notify, and no page that will show it.
281
+ */
282
+ public static getNothingSentReason(data: {
283
+ audience: IncidentSubscriberAudienceResult;
284
+ draftNothingSentReason: SubscriberNotificationPreviewNothingSentReason | null;
285
+ }): SubscriberNotificationPreviewNothingSentReason | null {
286
+ if (!data.audience.hasMonitors) {
287
+ return SubscriberNotificationPreviewNothingSentReason.NoMonitors;
288
+ }
289
+
290
+ if (data.audience.isHiddenFromStatusPages) {
291
+ return SubscriberNotificationPreviewNothingSentReason.HiddenFromStatusPages;
292
+ }
293
+
294
+ if (data.draftNothingSentReason) {
295
+ return data.draftNothingSentReason;
296
+ }
297
+
298
+ if (
299
+ data.audience.statusPages.length === 0 &&
300
+ data.audience.hiddenStatusPageCount === 0
301
+ ) {
302
+ return SubscriberNotificationPreviewNothingSentReason.NoStatusPages;
303
+ }
304
+
305
+ return null;
306
+ }
307
+
308
+ /*
309
+ * The request body of POST /preview. Anything that is not a request is
310
+ * refused with what is wrong, rather than previewed as something else.
311
+ */
312
+ public static parseRequest(
313
+ body: unknown,
314
+ ): SubscriberNotificationPreviewRequest {
315
+ const json: JSONObject = this.asObject(body, "The request");
316
+
317
+ if (json["event"] === SubscriberNotificationPreviewEvent.IncidentCreated) {
318
+ const incident: JSONObject = this.asObject(json["incident"], "incident");
319
+
320
+ const draft: SubscriberNotificationPreviewIncidentDraft = {
321
+ title: this.parseText(
322
+ incident["title"],
323
+ "incident.title",
324
+ SubscriberNotificationPreview.maxTitleLength,
325
+ ),
326
+ description: this.parseText(
327
+ incident["description"],
328
+ "incident.description",
329
+ SubscriberNotificationPreview.maxTextLength,
330
+ ),
331
+ incidentSeverityId:
332
+ incident["incidentSeverityId"] === undefined ||
333
+ incident["incidentSeverityId"] === null ||
334
+ incident["incidentSeverityId"] === ""
335
+ ? null
336
+ : this.parseId(
337
+ incident["incidentSeverityId"],
338
+ "incident.incidentSeverityId",
339
+ ),
340
+ monitorIds: this.parseIds(
341
+ incident["monitorIds"],
342
+ "incident.monitorIds",
343
+ ),
344
+ statusPageIds: this.parseIds(
345
+ incident["statusPageIds"],
346
+ "incident.statusPageIds",
347
+ ),
348
+ labelIds: this.parseIds(incident["labelIds"], "incident.labelIds"),
349
+ customFields: this.parseCustomFields(
350
+ incident["customFields"],
351
+ "incident.customFields",
352
+ ),
353
+ isPrivate: incident["isPrivate"] === true,
354
+ // On unless it is switched off, as it is on the form.
355
+ shouldStatusPageSubscribersBeNotifiedOnIncidentCreated:
356
+ incident["shouldStatusPageSubscribersBeNotifiedOnIncidentCreated"] !==
357
+ false,
358
+ };
359
+
360
+ return {
361
+ event: SubscriberNotificationPreviewEvent.IncidentCreated,
362
+ incident: draft,
363
+ };
364
+ }
365
+
366
+ if (
367
+ json["event"] ===
368
+ SubscriberNotificationPreviewEvent.IncidentPublicNoteCreated
369
+ ) {
370
+ return {
371
+ event: SubscriberNotificationPreviewEvent.IncidentPublicNoteCreated,
372
+ incidentId: this.parseId(json["incidentId"], "incidentId"),
373
+ note: this.parseText(
374
+ json["note"],
375
+ "note",
376
+ SubscriberNotificationPreview.maxTextLength,
377
+ ),
378
+ postedAt: this.parseDate(json["postedAt"], "postedAt"),
379
+ };
380
+ }
381
+
382
+ throw new BadDataException(
383
+ `event must be one of: ${Object.values(
384
+ SubscriberNotificationPreviewEvent,
385
+ ).join(", ")}.`,
386
+ );
387
+ }
388
+
389
+ /*
390
+ * The request body of POST /send-test: a preview request and the status
391
+ * page whose email to send. It takes no address: the test goes to the
392
+ * caller's own, and a toEmail in the body is not read.
393
+ */
394
+ public static parseSendTestRequest(
395
+ body: unknown,
396
+ ): SubscriberNotificationSendTestRequest {
397
+ const request: SubscriberNotificationPreviewRequest =
398
+ this.parseRequest(body);
399
+ const json: JSONObject = this.asObject(body, "The request");
400
+
401
+ return {
402
+ ...request,
403
+ statusPageId: this.parseId(json["statusPageId"], "statusPageId"),
404
+ };
405
+ }
406
+
407
+ // An incident being declared, from the form's values.
408
+ private static async resolveDraft(data: {
409
+ projectId: ObjectID;
410
+ props: DatabaseCommonInteractionProps;
411
+ draft: SubscriberNotificationPreviewIncidentDraft;
412
+ }): Promise<PreviewIncident> {
413
+ const draft: SubscriberNotificationPreviewIncidentDraft = data.draft;
414
+
415
+ const [severity, labels, customFieldDefinitions]: [
416
+ IncidentSeverity | null,
417
+ Array<Label>,
418
+ Array<CustomFieldDefinition>,
419
+ ] = await Promise.all([
420
+ this.readSeverity({
421
+ projectId: data.projectId,
422
+ incidentSeverityId: draft.incidentSeverityId,
423
+ }),
424
+ this.readLabels({
425
+ projectId: data.projectId,
426
+ labelIds: draft.labelIds,
427
+ }),
428
+ this.readCustomFieldDefinitions(data.projectId),
429
+ ]);
430
+
431
+ /*
432
+ * The values must fit their fields, as they must when the incident is
433
+ * declared: a preview of an incident that cannot be declared says why.
434
+ */
435
+ const customFieldErrors: ReturnType<typeof validateCustomFieldValues> =
436
+ validateCustomFieldValues({
437
+ definitions: customFieldDefinitions,
438
+ customFields: draft.customFields,
439
+ storedCustomFields: {},
440
+ });
441
+
442
+ if (customFieldErrors.length > 0) {
443
+ throw new BadDataException(
444
+ formatCustomFieldValueValidationErrors(customFieldErrors),
445
+ );
446
+ }
447
+
448
+ const incident: Incident = new Incident();
449
+ incident.projectId = data.projectId;
450
+ incident.title = draft.title;
451
+ incident.description = draft.description;
452
+ if (severity) {
453
+ incident.incidentSeverity = severity;
454
+ }
455
+ incident.labels = labels;
456
+ incident.customFields = { ...draft.customFields };
457
+ incident.monitors = draft.monitorIds.map((id: string): Monitor => {
458
+ const monitor: Monitor = new Monitor();
459
+ monitor._id = id;
460
+ return monitor;
461
+ });
462
+
463
+ /*
464
+ * The values a custom field mapping copies from the monitors, as
465
+ * declaring the incident adds them (IncidentService.onBeforeCreate).
466
+ */
467
+ await CustomFieldMappingService.applyMappingsToCreate({
468
+ definitionModelType: IncidentCustomField,
469
+ createBy: {
470
+ data: incident,
471
+ props: {
472
+ tenantId: data.projectId,
473
+ isRoot: true,
474
+ },
475
+ },
476
+ });
477
+
478
+ let draftNothingSentReason: SubscriberNotificationPreviewNothingSentReason | null =
479
+ null;
480
+
481
+ if (draft.isPrivate) {
482
+ draftNothingSentReason =
483
+ SubscriberNotificationPreviewNothingSentReason.PrivateIncident;
484
+ } else if (!draft.shouldStatusPageSubscribersBeNotifiedOnIncidentCreated) {
485
+ draftNothingSentReason =
486
+ SubscriberNotificationPreviewNothingSentReason.NotifyOff;
487
+ }
488
+
489
+ return {
490
+ event: SubscriberIncidentEmailEvent.IncidentCreated,
491
+ incident: incident,
492
+ audienceRequest: {
493
+ projectId: data.projectId,
494
+ props: data.props,
495
+ monitorIds: draft.monitorIds.map((id: string): ObjectID => {
496
+ return new ObjectID(id);
497
+ }),
498
+ statusPageIds: draft.statusPageIds.map((id: string): ObjectID => {
499
+ return new ObjectID(id);
500
+ }),
501
+ },
502
+ draftNothingSentReason: draftNothingSentReason,
503
+ };
504
+ }
505
+
506
+ /*
507
+ * A public note being written on an incident that exists. The incident is
508
+ * not read here: the audience reads it first, with the caller's own
509
+ * permissions (see build).
510
+ */
511
+ private static async resolvePublicNote(data: {
512
+ projectId: ObjectID;
513
+ props: DatabaseCommonInteractionProps;
514
+ incidentId: string;
515
+ note: string;
516
+ postedAt: Date | null;
517
+ }): Promise<PreviewIncident> {
518
+ return {
519
+ event: SubscriberIncidentEmailEvent.IncidentPublicNoteCreated,
520
+ incident: new Incident(),
521
+ note: {
522
+ text: data.note,
523
+ postedAt: data.postedAt,
524
+ },
525
+ audienceRequest: {
526
+ projectId: data.projectId,
527
+ props: data.props,
528
+ incidentId: new ObjectID(data.incidentId),
529
+ },
530
+ draftNothingSentReason: null,
531
+ };
532
+ }
533
+
534
+ /*
535
+ * What the public note job reads of the incident. Read as root: the caller
536
+ * has been shown to read the incident (the audience read it with their
537
+ * permissions), and these are its own title, severity, state, labels and
538
+ * custom field values.
539
+ */
540
+ private static async readIncidentContent(data: {
541
+ projectId: ObjectID;
542
+ incidentId: ObjectID;
543
+ }): Promise<Incident> {
544
+ const incident: Incident | null = await IncidentService.findOneBy({
545
+ query: {
546
+ _id: data.incidentId,
547
+ projectId: data.projectId,
548
+ },
549
+ select: {
550
+ _id: true,
551
+ title: true,
552
+ description: true,
553
+ projectId: true,
554
+ monitors: {
555
+ _id: true,
556
+ },
557
+ incidentSeverity: {
558
+ name: true,
559
+ },
560
+ currentIncidentState: {
561
+ name: true,
562
+ },
563
+ labels: {
564
+ name: true,
565
+ },
566
+ customFields: true,
567
+ },
568
+ props: {
569
+ isRoot: true,
570
+ },
571
+ });
572
+
573
+ // Deleted since the caller's read.
574
+ if (!incident) {
575
+ throw new NotFoundException("Incident not found");
576
+ }
577
+
578
+ return incident;
579
+ }
580
+
581
+ private static async readSeverity(data: {
582
+ projectId: ObjectID;
583
+ incidentSeverityId: string | null;
584
+ }): Promise<IncidentSeverity | null> {
585
+ if (!data.incidentSeverityId) {
586
+ return null;
587
+ }
588
+
589
+ const severity: IncidentSeverity | null =
590
+ await IncidentSeverityService.findOneBy({
591
+ query: {
592
+ _id: data.incidentSeverityId,
593
+ projectId: data.projectId,
594
+ },
595
+ select: {
596
+ _id: true,
597
+ name: true,
598
+ },
599
+ props: {
600
+ isRoot: true,
601
+ },
602
+ });
603
+
604
+ if (!severity) {
605
+ throw new BadDataException(
606
+ "This incident severity was not found in this project.",
607
+ );
608
+ }
609
+
610
+ return severity;
611
+ }
612
+
613
+ private static async readLabels(data: {
614
+ projectId: ObjectID;
615
+ labelIds: Array<string>;
616
+ }): Promise<Array<Label>> {
617
+ if (data.labelIds.length === 0) {
618
+ return [];
619
+ }
620
+
621
+ const labels: Array<Label> = await LabelService.findBy({
622
+ query: {
623
+ _id: QueryHelper.any(data.labelIds),
624
+ projectId: data.projectId,
625
+ },
626
+ select: {
627
+ _id: true,
628
+ name: true,
629
+ },
630
+ limit: data.labelIds.length,
631
+ skip: 0,
632
+ props: {
633
+ isRoot: true,
634
+ },
635
+ });
636
+
637
+ const found: Array<string> = labels.map((label: Label): string => {
638
+ return this.getId(label);
639
+ });
640
+
641
+ const isEveryLabelFound: boolean = data.labelIds.every(
642
+ (id: string): boolean => {
643
+ return found.includes(id);
644
+ },
645
+ );
646
+
647
+ if (!isEveryLabelFound) {
648
+ throw new BadDataException(
649
+ "One or more of these labels were not found in this project.",
650
+ );
651
+ }
652
+
653
+ return labels;
654
+ }
655
+
656
+ // The project's incident custom fields, as the values are checked against.
657
+ private static async readCustomFieldDefinitions(
658
+ projectId: ObjectID,
659
+ ): Promise<Array<CustomFieldDefinition>> {
660
+ const fields: Array<IncidentCustomField> =
661
+ await IncidentCustomFieldService.findBy({
662
+ query: {
663
+ projectId: projectId,
664
+ },
665
+ select: {
666
+ name: true,
667
+ customFieldType: true,
668
+ dropdownOptions: true,
669
+ },
670
+ limit: LIMIT_PER_PROJECT,
671
+ skip: 0,
672
+ props: {
673
+ isRoot: true,
674
+ },
675
+ });
676
+
677
+ const definitions: Array<CustomFieldDefinition> = [];
678
+
679
+ for (const field of fields) {
680
+ if (typeof field.name === "string") {
681
+ definitions.push({
682
+ name: field.name,
683
+ customFieldType: field.customFieldType,
684
+ dropdownOptions: field.dropdownOptions,
685
+ });
686
+ }
687
+ }
688
+
689
+ return definitions;
690
+ }
691
+
692
+ private static findAudiencePage(
693
+ audience: IncidentSubscriberAudienceResult,
694
+ statusPage: StatusPage,
695
+ ): IncidentSubscriberAudienceStatusPage | undefined {
696
+ const id: string = this.getId(statusPage);
697
+
698
+ return audience.statusPages.find(
699
+ (page: IncidentSubscriberAudienceStatusPage): boolean => {
700
+ return page.statusPageId.toLowerCase() === id;
701
+ },
702
+ );
703
+ }
704
+
705
+ private static getId(model: StatusPage | Label): string {
706
+ return (model._id || model.id?.toString() || "").toString().toLowerCase();
707
+ }
708
+
709
+ private static asObject(value: unknown, name: string): JSONObject {
710
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
711
+ throw new BadDataException(`${name} must be an object.`);
712
+ }
713
+
714
+ return value as JSONObject;
715
+ }
716
+
717
+ /*
718
+ * An incident's custom field values, bounded (see
719
+ * SubscriberNotificationPreview.maxCustomFieldCount): every value is
720
+ * rendered and goes into every page's email. Whether each value fits its
721
+ * field is checked with the field definitions, as declaring checks it.
722
+ */
723
+ private static parseCustomFields(value: unknown, name: string): JSONObject {
724
+ if (value === undefined || value === null) {
725
+ return {};
726
+ }
727
+
728
+ const customFields: JSONObject = this.asObject(value, name);
729
+
730
+ if (
731
+ Object.keys(customFields).length >
732
+ SubscriberNotificationPreview.maxCustomFieldCount
733
+ ) {
734
+ throw new BadDataException(
735
+ `${name} can have at most ${SubscriberNotificationPreview.maxCustomFieldCount} values.`,
736
+ );
737
+ }
738
+
739
+ let length: number = 0;
740
+
741
+ try {
742
+ length = JSON.stringify(customFields).length;
743
+ } catch {
744
+ throw new BadDataException(`${name} must be plain values.`);
745
+ }
746
+
747
+ if (length > SubscriberNotificationPreview.maxCustomFieldsLength) {
748
+ throw new BadDataException(
749
+ `${name} can be at most ${SubscriberNotificationPreview.maxCustomFieldsLength} characters long in all.`,
750
+ );
751
+ }
752
+
753
+ return customFields;
754
+ }
755
+
756
+ private static parseText(
757
+ value: unknown,
758
+ name: string,
759
+ maxLength: number,
760
+ ): string {
761
+ if (value === undefined || value === null) {
762
+ return "";
763
+ }
764
+
765
+ if (typeof value !== "string") {
766
+ throw new BadDataException(`${name} must be text.`);
767
+ }
768
+
769
+ if (value.length > maxLength) {
770
+ throw new BadDataException(
771
+ `${name} can be at most ${maxLength} characters long.`,
772
+ );
773
+ }
774
+
775
+ return value;
776
+ }
777
+
778
+ // An id, lower-cased as the database returns ids.
779
+ private static parseId(value: unknown, name: string): string {
780
+ let id: string = "";
781
+
782
+ if (typeof value === "string") {
783
+ id = value;
784
+ } else if (value instanceof ObjectID) {
785
+ id = value.toString();
786
+ } else if (value && typeof value === "object") {
787
+ id = new ObjectID(value as JSONObject).toString();
788
+ }
789
+
790
+ id = id.trim();
791
+
792
+ if (!id || !ObjectID.isValidUUID(id)) {
793
+ throw new BadDataException(`${name} must be a valid ID.`);
794
+ }
795
+
796
+ return id.toLowerCase();
797
+ }
798
+
799
+ private static parseIds(value: unknown, name: string): Array<string> {
800
+ if (value === undefined || value === null) {
801
+ return [];
802
+ }
803
+
804
+ if (!Array.isArray(value)) {
805
+ throw new BadDataException(`${name} must be a list of IDs.`);
806
+ }
807
+
808
+ if (value.length > IncidentSubscriberAudience.maxIdsPerRequest) {
809
+ throw new BadDataException(
810
+ `${name} can list at most ${IncidentSubscriberAudience.maxIdsPerRequest} IDs.`,
811
+ );
812
+ }
813
+
814
+ return IncidentScopeAddedPagesNotification.normalizeStatusPageIds(
815
+ value.map((item: unknown): string => {
816
+ return this.parseId(item, name);
817
+ }),
818
+ );
819
+ }
820
+
821
+ private static parseDate(value: unknown, name: string): Date | null {
822
+ if (value === undefined || value === null || value === "") {
823
+ return null;
824
+ }
825
+
826
+ if (typeof value !== "string" && !(value instanceof Date)) {
827
+ throw new BadDataException(`${name} must be a date.`);
828
+ }
829
+
830
+ // An ISO date as the dashboard sends it (Date.toISOString).
831
+ const date: Date = value instanceof Date ? value : new Date(value);
832
+
833
+ if (Number.isNaN(date.getTime())) {
834
+ throw new BadDataException(`${name} must be a date.`);
835
+ }
836
+
837
+ return date;
838
+ }
839
+ }