@oneuptime/common 14.0.7 → 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 (440) 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/StatusPage.ts +55 -0
  6. package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
  7. package/Server/API/IncidentAPI.ts +162 -0
  8. package/Server/API/StatusPageAPI.ts +487 -171
  9. package/Server/API/StatusPageSubscriberAPI.ts +63 -15
  10. package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  18. package/Server/Infrastructure/Semaphore.ts +10 -0
  19. package/Server/Middleware/IdentityRateLimit.ts +108 -3
  20. package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
  21. package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
  22. package/Server/Services/DatabaseService.ts +93 -10
  23. package/Server/Services/IncidentCustomFieldService.ts +276 -1
  24. package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
  25. package/Server/Services/IncidentEpisodeService.ts +15 -0
  26. package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
  27. package/Server/Services/IncidentPublicNoteService.ts +30 -1
  28. package/Server/Services/IncidentService.ts +1535 -65
  29. package/Server/Services/IncidentStateTimelineService.ts +13 -0
  30. package/Server/Services/IncidentTemplateService.ts +109 -0
  31. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
  32. package/Server/Services/ScheduledMaintenanceService.ts +68 -18
  33. package/Server/Services/SmsService.ts +10 -0
  34. package/Server/Services/StatusPageService.ts +65 -8
  35. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
  36. package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
  37. package/Server/Services/StatusPageSubscriberService.ts +1161 -64
  38. package/Server/Types/Markdown.ts +153 -6
  39. package/Server/Types/Workflow/Components/Email.ts +61 -2
  40. package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
  41. package/Server/Utils/DataSource/EgressGuard.ts +66 -21
  42. package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
  43. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
  44. package/Server/Utils/SSRFProtection.ts +76 -16
  45. package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
  46. package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
  47. package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
  48. package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
  49. package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
  50. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
  51. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
  52. package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
  53. package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
  54. package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
  55. package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
  56. package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
  57. package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
  58. package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
  59. package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
  60. package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
  61. package/Server/Utils/StatusPageResource.ts +51 -20
  62. package/Server/Utils/VM/VMAPI.ts +1 -0
  63. package/Server/Utils/VM/VMRunner.ts +10 -0
  64. package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
  65. package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
  66. package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
  67. package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
  68. package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
  69. package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
  70. package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
  71. package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
  72. package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
  73. package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
  74. package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
  75. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +242 -5
  76. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
  77. package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
  78. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
  79. package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
  80. package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
  81. package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
  82. package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
  83. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
  84. package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
  85. package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
  86. package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
  87. package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
  88. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
  89. package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
  90. package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
  91. package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
  92. package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
  93. package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
  94. package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
  95. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
  96. package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
  97. package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
  98. package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
  99. package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
  100. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
  101. package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
  102. package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
  103. package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
  104. package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
  105. package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
  106. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
  107. package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
  108. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
  109. package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
  110. package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
  111. package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
  112. package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
  113. package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
  114. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
  115. package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
  116. package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
  117. package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
  118. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
  119. package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
  120. package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
  121. package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
  122. package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
  123. package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
  124. package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
  125. package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
  126. package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
  127. package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
  128. package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
  129. package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
  130. package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
  131. package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
  132. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
  133. package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
  134. package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
  135. package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
  136. package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
  137. package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
  138. package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
  139. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
  140. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
  141. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
  142. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
  143. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
  144. package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
  145. package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
  146. package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
  147. package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
  148. package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
  149. package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
  150. package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
  151. package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
  152. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
  153. package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
  154. package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
  155. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
  156. package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
  157. package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
  158. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
  159. package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
  160. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
  161. package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
  162. package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
  163. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
  164. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
  165. package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
  166. package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
  167. package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
  168. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
  169. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
  170. package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
  171. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
  172. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
  173. package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
  174. package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
  175. package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
  176. package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
  177. package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
  178. package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
  179. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
  180. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
  181. package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
  182. package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
  183. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
  184. package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
  185. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
  186. package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
  187. package/Tests/Types/SafeHtml.test.ts +102 -0
  188. package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
  189. package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
  190. package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
  191. package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
  192. package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
  193. package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
  194. package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
  195. package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
  196. package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
  197. package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
  198. package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
  199. package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
  200. package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
  201. package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
  202. package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
  203. package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
  204. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
  205. package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
  206. package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
  207. package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
  208. package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
  209. package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
  210. package/Types/CustomField/CustomFieldOrder.ts +55 -0
  211. package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
  212. package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
  213. package/Types/CustomField/CustomFieldType.ts +14 -0
  214. package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
  215. package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
  216. package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
  217. package/Types/SafeHtml.ts +93 -0
  218. package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
  219. package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
  220. package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
  221. package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
  222. package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
  223. package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
  224. package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
  225. package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
  226. package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
  227. package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
  228. package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
  229. package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
  230. package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
  231. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
  232. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
  233. package/UI/Components/Forms/ModelForm.tsx +70 -8
  234. package/UI/Components/Forms/Validation.ts +1 -1
  235. package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
  236. package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
  237. package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
  238. package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
  239. package/UI/Components/ModelTable/ModelTable.tsx +6 -7
  240. package/UI/Utils/SensitiveUrlToken.ts +10 -5
  241. package/Utils/API.ts +247 -2
  242. package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
  243. package/Utils/Markdown/MarkdownEscape.ts +65 -0
  244. package/Utils/ProbeNetworkFailureUtil.ts +673 -0
  245. package/build/dist/Models/DatabaseModels/Incident.js +267 -1
  246. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  247. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
  248. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  249. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
  250. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  251. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
  252. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  253. package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
  254. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  255. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
  256. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  257. package/build/dist/Server/API/IncidentAPI.js +100 -1
  258. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  259. package/build/dist/Server/API/StatusPageAPI.js +417 -176
  260. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  261. package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
  262. package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
  263. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
  264. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
  265. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
  266. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
  267. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
  268. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
  269. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
  270. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
  271. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
  272. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
  273. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
  274. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
  275. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
  276. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
  277. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  278. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  279. package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
  280. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  281. package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
  282. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
  283. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
  284. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
  285. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
  286. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
  287. package/build/dist/Server/Services/DatabaseService.js +56 -7
  288. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  289. package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
  290. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  291. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
  292. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  293. package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
  294. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  295. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
  296. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  297. package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
  298. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  299. package/build/dist/Server/Services/IncidentService.js +1052 -0
  300. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  301. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  302. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  303. package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
  304. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  305. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
  306. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  307. package/build/dist/Server/Services/ScheduledMaintenanceService.js +47 -17
  308. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  309. package/build/dist/Server/Services/SmsService.js +2 -22
  310. package/build/dist/Server/Services/SmsService.js.map +1 -1
  311. package/build/dist/Server/Services/StatusPageService.js +47 -9
  312. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  313. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
  314. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  315. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
  316. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
  317. package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
  318. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  319. package/build/dist/Server/Types/Markdown.js +110 -6
  320. package/build/dist/Server/Types/Markdown.js.map +1 -1
  321. package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
  322. package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
  323. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
  324. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
  325. package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
  326. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  327. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
  328. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
  329. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
  330. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  331. package/build/dist/Server/Utils/SSRFProtection.js +48 -6
  332. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  333. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
  334. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
  335. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
  336. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
  337. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
  338. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
  339. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
  340. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
  341. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
  342. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
  343. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
  344. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
  345. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
  346. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
  347. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
  348. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
  349. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
  350. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
  351. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
  352. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
  353. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
  354. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
  355. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
  356. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
  357. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
  358. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
  359. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
  360. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
  361. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
  362. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
  363. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
  364. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
  365. package/build/dist/Server/Utils/StatusPageResource.js +39 -7
  366. package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
  367. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  368. package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
  369. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  370. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
  371. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
  372. package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
  373. package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
  374. package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
  375. package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
  376. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
  377. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
  378. package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
  379. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  380. package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
  381. package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
  382. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
  383. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
  384. package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
  385. package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
  386. package/build/dist/Types/SafeHtml.js +84 -0
  387. package/build/dist/Types/SafeHtml.js.map +1 -0
  388. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
  389. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
  390. package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
  391. package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
  392. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
  393. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
  394. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
  395. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
  396. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
  397. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
  398. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
  399. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
  400. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
  401. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
  402. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
  403. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
  404. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
  405. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
  406. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
  407. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
  408. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
  409. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
  410. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
  411. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
  412. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
  413. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
  414. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
  415. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
  416. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
  417. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  418. package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
  419. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  420. package/build/dist/UI/Components/Forms/Validation.js +1 -1
  421. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  422. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  423. package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
  424. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
  425. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  426. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
  427. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  428. package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
  429. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  430. package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
  431. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
  432. package/build/dist/Utils/API.js +177 -1
  433. package/build/dist/Utils/API.js.map +1 -1
  434. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
  435. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
  436. package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
  437. package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
  438. package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
  439. package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
  440. package/package.json +1 -1
@@ -0,0 +1,722 @@
1
+ import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
2
+ import StatusPageSubscriberNotificationMethod from "../../../Types/StatusPage/StatusPageSubscriberNotificationMethod";
3
+ import StatusPageSubscriberUnsubscribe from "../../../Types/StatusPage/StatusPageSubscriberUnsubscribe";
4
+ import { escapeMarkdownInline } from "../../../Utils/Markdown/MarkdownEscape";
5
+ import logger, { EXTERNAL_FAULT } from "../Logger";
6
+ import { StatusPageExclusionReason, } from "./StatusPageExclusion";
7
+ import SubscriberNotificationTiming from "./SubscriberNotificationTiming";
8
+ /*
9
+ * What one subscriber send - an incident created, a state change, a public
10
+ * note, a postmortem, or the episode equivalents - did on each status page it
11
+ * went to. It does three jobs for the send:
12
+ *
13
+ * - Email and SMS once per address. For an incident limited to specific
14
+ * status pages (see IncidentStatusPageScope), someone subscribed on two of
15
+ * the selected pages - a regional manager on Site 03 and Site 07 - gets one
16
+ * email, not two. Pages are visited in name order, so the first page's
17
+ * template, branding and unsubscribe link are the ones they get. Webhook,
18
+ * Slack and Teams deliveries are never merged: their payloads carry the
19
+ * page they are for (statusPageId, resourcesAffected, unsubscribeUrl), and
20
+ * an integration listening per page must see every page. An unscoped
21
+ * incident sends exactly as it always has, one message per subscription.
22
+ * The addresses are remembered for this send only. An address counts as
23
+ * sent only once its message was: one whose message failed - its page's
24
+ * own SMTP or Twilio is down, say - or whose handler threw before sending
25
+ * is freed again (deliver, releaseUndeliveredAddresses), so a later page
26
+ * that has it sends it rather than counting it as already sent.
27
+ * - Delivery (deliver): each message is awaited, and counted sent or failed.
28
+ * A failure is a send that throws (an unreachable host, a refused URL), one
29
+ * that answers with an HTTPErrorResponse (the Notification service's email
30
+ * and SMS endpoints, and the Slack and webhook senders, return one rather
31
+ * than throw), or one still unanswered after
32
+ * SubscriberNotificationTiming.SEND_TIMEOUT_IN_MS. The SMS endpoint
33
+ * answers success for an SMS the project deliberately does not send -
34
+ * SMS notifications turned off, too little SMS balance - unless the
35
+ * request asks otherwise, so the jobs send with SmsService's
36
+ * failIfNotSent: such an SMS then answers with an error and counts as
37
+ * failed, and a page reached that way is not recorded as told.
38
+ * - A record of it: for the incident (or episode) feed item, each page, the
39
+ * subject its email went out with, and how many messages were sent and
40
+ * failed on each channel, plus the pages that were left out and why; and
41
+ * the same counts, in plain text, for the notification's status message.
42
+ * A page "succeeded" when every one of its subscribers was reached and no
43
+ * message to them failed; the incident created notification records only
44
+ * those pages as told, so Retry resumes after them.
45
+ */
46
+ export var StatusPageDeliverySkipReason;
47
+ (function (StatusPageDeliverySkipReason) {
48
+ // The status page does not show incidents (showIncidentsOnStatusPage off).
49
+ StatusPageDeliverySkipReason["HidesIncidents"] = "HidesIncidents";
50
+ // The status page does not show episodes (showEpisodesOnStatusPage off).
51
+ StatusPageDeliverySkipReason["HidesEpisodes"] = "HidesEpisodes";
52
+ // Already sent this notification (Incident.statusPagesNotifiedOnCreation).
53
+ StatusPageDeliverySkipReason["AlreadyNotified"] = "AlreadyNotified";
54
+ // Sending to this page failed part-way.
55
+ StatusPageDeliverySkipReason["Failed"] = "Failed";
56
+ /*
57
+ * The send ran out of time (SubscriberNotificationTiming.SEND_WINDOW_IN_MS)
58
+ * before it reached every subscriber of this page, or before it reached
59
+ * the page at all.
60
+ */
61
+ StatusPageDeliverySkipReason["OutOfTime"] = "OutOfTime";
62
+ })(StatusPageDeliverySkipReason || (StatusPageDeliverySkipReason = {}));
63
+ /*
64
+ * What Retry does after a send that did not reach everyone, for the status
65
+ * message to say so.
66
+ */
67
+ export var SubscriberNotificationRetryScope;
68
+ (function (SubscriberNotificationRetryScope) {
69
+ /*
70
+ * The incident created notification: Retry sends only to the pages not
71
+ * sent it in full (Incident.statusPagesNotifiedOnCreation).
72
+ */
73
+ SubscriberNotificationRetryScope["PagesNotYetSent"] = "PagesNotYetSent";
74
+ // Everything else: Retry sends to every page again.
75
+ SubscriberNotificationRetryScope["EveryPage"] = "EveryPage";
76
+ })(SubscriberNotificationRetryScope || (SubscriberNotificationRetryScope = {}));
77
+ // The order channels are listed in, and what each is called.
78
+ const METHOD_LABELS = [
79
+ [StatusPageSubscriberNotificationMethod.Email, "email"],
80
+ [StatusPageSubscriberNotificationMethod.SMS, "SMS"],
81
+ [StatusPageSubscriberNotificationMethod.Slack, "Slack"],
82
+ [StatusPageSubscriberNotificationMethod.MicrosoftTeams, "Microsoft Teams"],
83
+ [StatusPageSubscriberNotificationMethod.Webhook, "webhook"],
84
+ ];
85
+ // Why a page was passed over, for a page the send never started on.
86
+ const SKIP_REASON_TEXT = {
87
+ [StatusPageDeliverySkipReason.HidesIncidents]: "not sent, this status page does not show incidents",
88
+ [StatusPageDeliverySkipReason.HidesEpisodes]: "not sent, this status page does not show episodes",
89
+ [StatusPageDeliverySkipReason.AlreadyNotified]: "not sent again, its subscribers were already sent this notification",
90
+ [StatusPageDeliverySkipReason.Failed]: "Sending to this status page failed part-way",
91
+ [StatusPageDeliverySkipReason.OutOfTime]: "not sent, the send ran out of time before it reached this status page",
92
+ };
93
+ // Said after the counts of a page the send stopped part-way through.
94
+ const STOPPED_PART_WAY_TEXT = {
95
+ [StatusPageDeliverySkipReason.Failed]: "Sending to this status page failed part-way, so some of its subscribers may not have been sent it.",
96
+ [StatusPageDeliverySkipReason.OutOfTime]: "The send ran out of time part-way through this status page, so some of its subscribers were not sent it.",
97
+ };
98
+ const EXCLUSION_HEADINGS = {
99
+ [StatusPageExclusionReason.OutsideIncidentScope]: {
100
+ one: "status page outside the status pages this is limited to",
101
+ many: "status pages outside the status pages this is limited to",
102
+ },
103
+ [StatusPageExclusionReason.OnlyShowsScopedIncidents]: {
104
+ one: "status page that only shows incidents limited to it",
105
+ many: "status pages that only show incidents limited to them",
106
+ },
107
+ };
108
+ // How many names a list of left-out pages shows before summing up the rest.
109
+ const MAX_LISTED_EXCLUDED_PAGES = 25;
110
+ // How many pages the status message lists before summing up the rest.
111
+ const MAX_LISTED_STATUS_MESSAGE_PAGES = 25;
112
+ export default class SubscriberNotificationDeliveryRecord {
113
+ constructor(data) {
114
+ var _a;
115
+ this.deliveries = [];
116
+ this.sentEmails = new Map();
117
+ this.sentPhones = new Map();
118
+ this.excludedStatusPages = [];
119
+ this.subscriberMatched = false;
120
+ this.dedupeEmailAndSms = data.dedupeEmailAndSms;
121
+ this.sendTimeoutInMs =
122
+ (_a = data.sendTimeoutInMs) !== null && _a !== void 0 ? _a : SubscriberNotificationTiming.SEND_TIMEOUT_IN_MS;
123
+ }
124
+ // The name a status page goes by in the feed: its name in the dashboard.
125
+ static getStatusPageName(statusPage) {
126
+ var _a, _b;
127
+ return (((_a = statusPage.name) === null || _a === void 0 ? void 0 : _a.trim()) ||
128
+ ((_b = statusPage.pageTitle) === null || _b === void 0 ? void 0 : _b.trim()) ||
129
+ "Untitled status page");
130
+ }
131
+ // The form addresses are compared in: trimmed, lower-cased.
132
+ static normalizeEmail(email) {
133
+ return email.toString().trim().toLowerCase();
134
+ }
135
+ // The form phone numbers are compared in: digits, with a leading +.
136
+ static normalizePhone(phone) {
137
+ const text = phone.toString().trim();
138
+ const digits = text.replace(/\D/g, "");
139
+ return text.startsWith("+") ? `+${digits}` : digits;
140
+ }
141
+ // A status page the send is about to go to, in the order they are visited.
142
+ startStatusPage(statusPage) {
143
+ this.getOrCreateDelivery(statusPage).started = true;
144
+ }
145
+ // Every subscriber of a status page the send started on was reached.
146
+ finishStatusPage(statusPage) {
147
+ this.getOrCreateDelivery(statusPage).finished = true;
148
+ }
149
+ // A status page the send passed over or stopped part-way through, and why.
150
+ skipStatusPage(statusPage, reason) {
151
+ this.getOrCreateDelivery(statusPage).skipReason = reason;
152
+ }
153
+ /*
154
+ * A subscriber whose preferences let this send through: it is sent
155
+ * something, unless its address already was through an earlier page.
156
+ */
157
+ recordSubscriberMatched() {
158
+ this.subscriberMatched = true;
159
+ }
160
+ // Whether any subscriber's preferences let this send through.
161
+ hasMatchedAnySubscriber() {
162
+ return this.subscriberMatched;
163
+ }
164
+ // Pages the incident's monitors reach that its scope left out.
165
+ addExcludedStatusPages(excludedStatusPages) {
166
+ this.excludedStatusPages.push(...excludedStatusPages);
167
+ }
168
+ /*
169
+ * Whether to email this address on this page. With dedupe on, an address
170
+ * already emailed in this send is not emailed again, and that is counted
171
+ * against the page; otherwise always yes.
172
+ */
173
+ shouldSendEmail(data) {
174
+ return this.claim({
175
+ statusPage: data.statusPage,
176
+ address: SubscriberNotificationDeliveryRecord.normalizeEmail(data.email),
177
+ sent: this.sentEmails,
178
+ method: StatusPageSubscriberNotificationMethod.Email,
179
+ });
180
+ }
181
+ // As shouldSendEmail, for a phone number and SMS.
182
+ shouldSendSms(data) {
183
+ return this.claim({
184
+ statusPage: data.statusPage,
185
+ address: SubscriberNotificationDeliveryRecord.normalizePhone(data.phone),
186
+ sent: this.sentPhones,
187
+ method: StatusPageSubscriberNotificationMethod.SMS,
188
+ });
189
+ }
190
+ /*
191
+ * Send one message and wait for the answer, counting it sent or failed on
192
+ * its page and channel. True when it was sent. Never throws: a failed
193
+ * message is recorded and logged, and the send goes on to the next one.
194
+ *
195
+ * An email passes its subject; the first one on a page is the one the
196
+ * feed shows. An email or SMS passes `to`, the address shouldSendEmail or
197
+ * shouldSendSms let through: sent, it stays taken for the rest of this
198
+ * send; failed, it is freed, so a later page that has it sends it.
199
+ */
200
+ async deliver(data) {
201
+ var _a;
202
+ let failed = false;
203
+ let failure = undefined;
204
+ try {
205
+ const result = await this.waitForAnswer(data.send);
206
+ if (result instanceof HTTPErrorResponse) {
207
+ failed = true;
208
+ failure = result;
209
+ }
210
+ }
211
+ catch (err) {
212
+ // Whatever was thrown, even nothing at all.
213
+ failed = true;
214
+ failure = err;
215
+ }
216
+ this.settleAddress({
217
+ method: data.method,
218
+ to: data.to,
219
+ sent: !failed,
220
+ });
221
+ if (!failed) {
222
+ this.recordSent({
223
+ statusPage: data.statusPage,
224
+ method: data.method,
225
+ subject: data.subject,
226
+ });
227
+ return true;
228
+ }
229
+ this.recordFailed({
230
+ statusPage: data.statusPage,
231
+ method: data.method,
232
+ subject: data.subject,
233
+ });
234
+ /*
235
+ * Delivery to a channel the SUBSCRIBER chose: their mailbox, their
236
+ * phone, their Slack/Teams webhook, their HTTP endpoint. A bounce, a
237
+ * 404 on a deleted webhook or an unreachable host is their side of the
238
+ * wire, not a OneUptime defect - and one status page can fan out to
239
+ * thousands of subscribers, so leaving these at ERROR buries real
240
+ * failures under a single tenant's dead webhook. What failed is counted
241
+ * in the record; the error itself (which can carry a subscriber's
242
+ * webhook URL) stays in the server log.
243
+ */
244
+ logger.error(`Subscriber ${data.method} notification failed on status page ${this.normalizeId(data.statusPage._id || ((_a = data.statusPage.id) === null || _a === void 0 ? void 0 : _a.toString()) || "")}: ${describeFailure(failure)}`, Object.assign(Object.assign({}, EXTERNAL_FAULT), (data.logAttributes || {})));
245
+ return false;
246
+ }
247
+ // A message sent on a status page.
248
+ recordSent(data) {
249
+ const delivery = this.getOrCreateDelivery(data.statusPage);
250
+ increment(delivery.sent, data.method);
251
+ this.recordSubject(delivery, data.subject);
252
+ }
253
+ // A message that could not be sent on a status page.
254
+ recordFailed(data) {
255
+ const delivery = this.getOrCreateDelivery(data.statusPage);
256
+ increment(delivery.failed, data.method);
257
+ this.recordSubject(delivery, data.subject);
258
+ }
259
+ // How many messages were sent on a status page, on one channel or all.
260
+ getSentCount(statusPageId, method) {
261
+ var _a;
262
+ return countOf((_a = this.findDelivery(statusPageId)) === null || _a === void 0 ? void 0 : _a.sent, method);
263
+ }
264
+ // How many messages failed on a status page, on one channel or all.
265
+ getFailedCount(statusPageId, method) {
266
+ var _a;
267
+ return countOf((_a = this.findDelivery(statusPageId)) === null || _a === void 0 ? void 0 : _a.failed, method);
268
+ }
269
+ // The subject the email on a status page went out with, if one did.
270
+ getSubject(statusPageId) {
271
+ var _a;
272
+ return (_a = this.findDelivery(statusPageId)) === null || _a === void 0 ? void 0 : _a.subject;
273
+ }
274
+ // Whether any message was sent or tried, on any page.
275
+ hasAttemptedAny() {
276
+ return this.deliveries.some((delivery) => {
277
+ return countOf(delivery.sent) + countOf(delivery.failed) > 0;
278
+ });
279
+ }
280
+ /*
281
+ * Whether the send fell short anywhere: a message failed, a page failed
282
+ * part-way, or the send ran out of time before it reached everyone.
283
+ */
284
+ hasFailures() {
285
+ return this.deliveries.some((delivery) => {
286
+ return isShortfall(delivery);
287
+ });
288
+ }
289
+ /*
290
+ * Whether every subscriber of a status page was reached and nobody's
291
+ * message failed: the page was sent this in full, and a retry need not
292
+ * go back to it.
293
+ */
294
+ didStatusPageSucceed(statusPageId) {
295
+ const delivery = this.findDelivery(statusPageId);
296
+ return Boolean(delivery &&
297
+ delivery.started &&
298
+ delivery.finished &&
299
+ !isShortfall(delivery));
300
+ }
301
+ // How many messages were sent and failed across every page.
302
+ getTotals() {
303
+ let sent = 0;
304
+ let failed = 0;
305
+ for (const delivery of this.deliveries) {
306
+ sent += countOf(delivery.sent);
307
+ failed += countOf(delivery.failed);
308
+ }
309
+ return { sent, failed };
310
+ }
311
+ /*
312
+ * The record as Markdown for the incident (or episode) feed item: one line
313
+ * per status page with what was sent and failed and the subject, the pages
314
+ * passed over and why, and the pages the scope left out. Empty when the
315
+ * send touched no status page at all.
316
+ */
317
+ toMarkdown() {
318
+ const sections = [];
319
+ if (this.deliveries.length > 0) {
320
+ const lines = this.deliveries.map((delivery) => {
321
+ return `- **${escapeMarkdownInline(delivery.statusPageName)}**: ${this.describeDelivery(delivery)}`;
322
+ });
323
+ sections.push(`**Status pages:**\n\n${lines.join("\n")}`);
324
+ if (this.dedupeEmailAndSms) {
325
+ sections.push("Email and SMS were sent once per address across these status pages, because this is limited to specific status pages. Someone subscribed on more than one of them got the message of the first page in this list.");
326
+ }
327
+ }
328
+ for (const reason of [
329
+ StatusPageExclusionReason.OutsideIncidentScope,
330
+ StatusPageExclusionReason.OnlyShowsScopedIncidents,
331
+ ]) {
332
+ const names = this.excludedStatusPages
333
+ .filter((excluded) => {
334
+ return excluded.reason === reason;
335
+ })
336
+ .map((excluded) => {
337
+ return escapeMarkdownInline(SubscriberNotificationDeliveryRecord.getStatusPageName(excluded.statusPage));
338
+ });
339
+ if (names.length === 0) {
340
+ continue;
341
+ }
342
+ const listed = names.slice(0, MAX_LISTED_EXCLUDED_PAGES);
343
+ const more = names.length - listed.length;
344
+ sections.push(`**Not sent to ${names.length} ${names.length === 1 ? EXCLUSION_HEADINGS[reason].one : EXCLUSION_HEADINGS[reason].many}:** ${listed.join(", ")}${more > 0 ? `, and ${more} more` : ""}.`);
345
+ }
346
+ return sections.join("\n\n");
347
+ }
348
+ /*
349
+ * The notification's status message, in plain text: whether everyone was
350
+ * sent it, then what was sent and failed on each status page the send
351
+ * went to - "Site 03: 41 email sent. Site 07: 16 email sent, 2 failed." -
352
+ * and, when it fell short, what Retry will do.
353
+ *
354
+ * `sentMessage` is the job's own line for a send that reached everyone.
355
+ * Pages passed over (they hide incidents, or were already sent it) are in
356
+ * the feed item, not here - unless the send went to no page at all. Then
357
+ * the message says so, and why: every page was left out by the scope,
358
+ * passed over, or there was none. "Sent successfully to all subscribers"
359
+ * would tell whoever reads the badge that subscribers heard when nobody
360
+ * did - the usual outcome, for an incident created on a monitor that only
361
+ * pages showing scoped incidents list.
362
+ */
363
+ toStatusMessage(data) {
364
+ if (!this.hasFailures() && !this.hasStartedAnyStatusPage()) {
365
+ return this.describeNoStatusPageSent();
366
+ }
367
+ const parts = [];
368
+ const { sent, failed } = this.getTotals();
369
+ if (!this.hasFailures()) {
370
+ parts.push(data.sentMessage);
371
+ }
372
+ else {
373
+ parts.push(failed > 0
374
+ ? `Not every subscriber was sent this notification: ${failed} of ${sent + failed} message${sent + failed === 1 ? "" : "s"} failed.`
375
+ : "Not every subscriber was sent this notification.");
376
+ if (this.deliveries.some((delivery) => {
377
+ return delivery.skipReason === StatusPageDeliverySkipReason.OutOfTime;
378
+ })) {
379
+ parts.push("The send ran out of time before it reached every subscriber.");
380
+ }
381
+ if (this.deliveries.some((delivery) => {
382
+ return delivery.skipReason === StatusPageDeliverySkipReason.Failed;
383
+ })) {
384
+ parts.push("Sending to a status page failed part-way.");
385
+ }
386
+ }
387
+ const reported = this.deliveries.filter((delivery) => {
388
+ return delivery.started || isShortfall(delivery);
389
+ });
390
+ const listed = reported.slice(0, MAX_LISTED_STATUS_MESSAGE_PAGES);
391
+ for (const delivery of listed) {
392
+ parts.push(`${toPlainText(delivery.statusPageName)}: ${this.describeForStatusMessage(delivery)}.`);
393
+ }
394
+ if (reported.length > listed.length) {
395
+ parts.push(`And ${reported.length - listed.length} more status page${reported.length - listed.length === 1 ? "" : "s"}.`);
396
+ }
397
+ if (this.hasFailures()) {
398
+ if (data.retryScope === SubscriberNotificationRetryScope.PagesNotYetSent) {
399
+ const notSent = this.deliveries
400
+ .filter((delivery) => {
401
+ return isShortfall(delivery);
402
+ })
403
+ .map((delivery) => {
404
+ return toPlainText(delivery.statusPageName);
405
+ });
406
+ parts.push(`Retry sends it again only to the status pages that were not sent it in full${notSent.length > 0 ? `: ${joinNames(notSent)}` : ""}.`);
407
+ }
408
+ else {
409
+ parts.push("Retry sends it again to every status page, including the subscribers who already got it.");
410
+ }
411
+ }
412
+ return parts.join(" ");
413
+ }
414
+ // Whether the send went to any status page, whatever it then sent there.
415
+ hasStartedAnyStatusPage() {
416
+ return this.deliveries.some((delivery) => {
417
+ return delivery.started;
418
+ });
419
+ }
420
+ /*
421
+ * The status message of a send that went to no status page: the pages the
422
+ * scope left out, by reason, and the ones passed over, each with why.
423
+ */
424
+ describeNoStatusPageSent() {
425
+ const parts = [
426
+ "Not sent to any subscriber: no status page was sent this notification.",
427
+ ];
428
+ const leftOut = [];
429
+ for (const reason of [
430
+ StatusPageExclusionReason.OutsideIncidentScope,
431
+ StatusPageExclusionReason.OnlyShowsScopedIncidents,
432
+ ]) {
433
+ const count = this.excludedStatusPages.filter((excluded) => {
434
+ return excluded.reason === reason;
435
+ }).length;
436
+ if (count > 0) {
437
+ leftOut.push(`${count} ${count === 1 ? EXCLUSION_HEADINGS[reason].one : EXCLUSION_HEADINGS[reason].many}`);
438
+ }
439
+ }
440
+ if (leftOut.length > 0) {
441
+ parts.push(`Left out by its status page scope: ${leftOut.join("; ")}.`);
442
+ }
443
+ const passedOver = this.deliveries.filter((delivery) => {
444
+ return isPassedOver(delivery);
445
+ });
446
+ const listed = passedOver.slice(0, MAX_LISTED_STATUS_MESSAGE_PAGES);
447
+ for (const delivery of listed) {
448
+ parts.push(`${toPlainText(delivery.statusPageName)}: ${SKIP_REASON_TEXT[delivery.skipReason]}.`);
449
+ }
450
+ if (passedOver.length > listed.length) {
451
+ parts.push(`And ${passedOver.length - listed.length} more status page${passedOver.length - listed.length === 1 ? "" : "s"}.`);
452
+ }
453
+ if (leftOut.length === 0 && passedOver.length === 0) {
454
+ parts.push("No status page lists what it is about.");
455
+ }
456
+ return parts.join(" ");
457
+ }
458
+ describeDelivery(delivery) {
459
+ if (isPassedOver(delivery)) {
460
+ return `${SKIP_REASON_TEXT[delivery.skipReason]}.`;
461
+ }
462
+ let text = `${this.describeCounts(delivery)}.`;
463
+ const stoppedPartWay = delivery.skipReason
464
+ ? STOPPED_PART_WAY_TEXT[delivery.skipReason]
465
+ : undefined;
466
+ if (stoppedPartWay) {
467
+ text += ` ${stoppedPartWay}`;
468
+ }
469
+ const alreadyEmailed = delivery.alreadySent.get(StatusPageSubscriberNotificationMethod.Email) ||
470
+ 0;
471
+ const alreadyTexted = delivery.alreadySent.get(StatusPageSubscriberNotificationMethod.SMS) || 0;
472
+ const alreadySent = [];
473
+ if (alreadyEmailed > 0) {
474
+ alreadySent.push(`${alreadyEmailed} email address${alreadyEmailed === 1 ? "" : "es"}`);
475
+ }
476
+ if (alreadyTexted > 0) {
477
+ alreadySent.push(`${alreadyTexted} phone number${alreadyTexted === 1 ? "" : "s"}`);
478
+ }
479
+ if (alreadySent.length > 0) {
480
+ text += ` Not sent again to ${alreadySent.join(" and ")} already sent it through another status page.`;
481
+ }
482
+ if (delivery.subject !== undefined) {
483
+ text += ` Subject: "${escapeMarkdownInline(delivery.subject)}".`;
484
+ }
485
+ return text;
486
+ }
487
+ // One page's line in the status message, without the page's name.
488
+ describeForStatusMessage(delivery) {
489
+ if (isPassedOver(delivery)) {
490
+ return SKIP_REASON_TEXT[delivery.skipReason];
491
+ }
492
+ const counts = this.describeCounts(delivery);
493
+ if (delivery.skipReason === StatusPageDeliverySkipReason.OutOfTime) {
494
+ return `${counts}, then the send ran out of time`;
495
+ }
496
+ if (delivery.skipReason === StatusPageDeliverySkipReason.Failed) {
497
+ return `${counts}, then sending failed part-way`;
498
+ }
499
+ return counts;
500
+ }
501
+ /*
502
+ * What was sent and what failed on a page, by channel: "41 email, 3
503
+ * webhook sent" or "16 email sent; 2 email, 1 SMS failed".
504
+ */
505
+ describeCounts(delivery) {
506
+ const sent = describeByChannel(delivery.sent);
507
+ const failed = describeByChannel(delivery.failed);
508
+ if (sent.length === 0 && failed.length === 0) {
509
+ return delivery.skipReason || countOf(delivery.alreadySent) > 0
510
+ ? "nothing sent"
511
+ : "nothing sent, no subscriber matched";
512
+ }
513
+ const sentText = sent.length > 0 ? `${sent.join(", ")} sent` : "nothing sent";
514
+ return failed.length > 0
515
+ ? `${sentText}; ${failed.join(", ")} failed`
516
+ : sentText;
517
+ }
518
+ recordSubject(delivery, subject) {
519
+ if (subject === undefined || delivery.subject !== undefined) {
520
+ return;
521
+ }
522
+ /*
523
+ * The feed is read by everyone who can read the incident. A custom
524
+ * subject template can carry {{unsubscribeUrl}}, whose token belongs to
525
+ * the one subscriber that email went to, so the feed keeps the link
526
+ * with its token redacted.
527
+ */
528
+ delivery.subject =
529
+ StatusPageSubscriberUnsubscribe.redactCredentials(subject);
530
+ }
531
+ /*
532
+ * The send's answer, or a rejection once it has gone unanswered for the
533
+ * send timeout. The request itself is not cancelled; this only stops
534
+ * waiting for it, so one hanging endpoint cannot hold a slot of the send
535
+ * forever.
536
+ */
537
+ async waitForAnswer(send) {
538
+ let timer;
539
+ try {
540
+ return await Promise.race([
541
+ send(),
542
+ new Promise((_resolve, reject) => {
543
+ timer = setTimeout(() => {
544
+ reject(new Error(`No answer after ${Math.round(this.sendTimeoutInMs / 1000)} seconds.`));
545
+ }, this.sendTimeoutInMs);
546
+ }),
547
+ ]);
548
+ }
549
+ finally {
550
+ if (timer !== undefined) {
551
+ clearTimeout(timer);
552
+ }
553
+ }
554
+ }
555
+ /*
556
+ * Free the addresses a page reserved and never sent to: its handler threw
557
+ * before sending, or the page stopped part-way. Called once every handler
558
+ * of the page has finished (SubscriberNotificationFanOut), so none of them
559
+ * is still sending; pages are visited one after another, so a later page
560
+ * that has one of these addresses then sends it.
561
+ */
562
+ releaseUndeliveredAddresses(statusPage) {
563
+ var _a;
564
+ const statusPageId = this.normalizeId(statusPage._id || ((_a = statusPage.id) === null || _a === void 0 ? void 0 : _a.toString()) || "");
565
+ for (const reservations of [this.sentEmails, this.sentPhones]) {
566
+ for (const [address, reservation] of Array.from(reservations)) {
567
+ if (!reservation.sent && reservation.statusPageId === statusPageId) {
568
+ reservations.delete(address);
569
+ }
570
+ }
571
+ }
572
+ }
573
+ /*
574
+ * What a delivered email or SMS means for its address: taken for the rest
575
+ * of this send when it went out, freed when it failed.
576
+ */
577
+ settleAddress(data) {
578
+ if (!this.dedupeEmailAndSms || data.to === undefined) {
579
+ return;
580
+ }
581
+ let reservations;
582
+ let address;
583
+ if (data.method === StatusPageSubscriberNotificationMethod.Email) {
584
+ reservations = this.sentEmails;
585
+ address = SubscriberNotificationDeliveryRecord.normalizeEmail(data.to.toString());
586
+ }
587
+ else if (data.method === StatusPageSubscriberNotificationMethod.SMS) {
588
+ reservations = this.sentPhones;
589
+ address = SubscriberNotificationDeliveryRecord.normalizePhone(data.to.toString());
590
+ }
591
+ else {
592
+ return;
593
+ }
594
+ const reservation = reservations.get(address);
595
+ if (!reservation) {
596
+ return;
597
+ }
598
+ if (data.sent) {
599
+ reservation.sent = true;
600
+ return;
601
+ }
602
+ reservations.delete(address);
603
+ }
604
+ claim(data) {
605
+ var _a;
606
+ if (!this.dedupeEmailAndSms || !data.address) {
607
+ return true;
608
+ }
609
+ if (!data.sent.has(data.address)) {
610
+ data.sent.set(data.address, {
611
+ statusPageId: this.normalizeId(data.statusPage._id || ((_a = data.statusPage.id) === null || _a === void 0 ? void 0 : _a.toString()) || ""),
612
+ sent: false,
613
+ });
614
+ return true;
615
+ }
616
+ const delivery = this.getOrCreateDelivery(data.statusPage);
617
+ increment(delivery.alreadySent, data.method);
618
+ return false;
619
+ }
620
+ findDelivery(statusPageId) {
621
+ const id = this.normalizeId(statusPageId);
622
+ return this.deliveries.find((item) => {
623
+ return item.statusPageId === id;
624
+ });
625
+ }
626
+ getOrCreateDelivery(statusPage) {
627
+ var _a;
628
+ const statusPageId = this.normalizeId(statusPage._id || ((_a = statusPage.id) === null || _a === void 0 ? void 0 : _a.toString()) || "");
629
+ let delivery = this.findDelivery(statusPageId);
630
+ if (!delivery) {
631
+ delivery = {
632
+ statusPageId: statusPageId,
633
+ statusPageName: SubscriberNotificationDeliveryRecord.getStatusPageName(statusPage),
634
+ started: false,
635
+ finished: false,
636
+ sent: new Map(),
637
+ failed: new Map(),
638
+ alreadySent: new Map(),
639
+ };
640
+ this.deliveries.push(delivery);
641
+ }
642
+ return delivery;
643
+ }
644
+ normalizeId(id) {
645
+ return id.toString().trim().toLowerCase();
646
+ }
647
+ }
648
+ /*
649
+ * A page the send never went to: it hides incidents or episodes, it was
650
+ * already sent this notification, or the send ran out of time before it got
651
+ * there. Its line is the reason alone.
652
+ */
653
+ function isPassedOver(delivery) {
654
+ if (!delivery.skipReason) {
655
+ return false;
656
+ }
657
+ if (delivery.skipReason === StatusPageDeliverySkipReason.OutOfTime) {
658
+ return !delivery.started;
659
+ }
660
+ return delivery.skipReason !== StatusPageDeliverySkipReason.Failed;
661
+ }
662
+ /*
663
+ * A page the send fell short on: a message to one of its subscribers
664
+ * failed, sending to it failed part-way, or the send ran out of time before
665
+ * it reached every subscriber.
666
+ */
667
+ function isShortfall(delivery) {
668
+ return (countOf(delivery.failed) > 0 ||
669
+ delivery.skipReason === StatusPageDeliverySkipReason.Failed ||
670
+ delivery.skipReason === StatusPageDeliverySkipReason.OutOfTime);
671
+ }
672
+ // "41 email, 3 webhook": each channel with a count, in METHOD_LABELS order.
673
+ function describeByChannel(counts) {
674
+ return METHOD_LABELS.filter(([method]) => {
675
+ return (counts.get(method) || 0) > 0;
676
+ }).map(([method, label]) => {
677
+ return `${counts.get(method)} ${label}`;
678
+ });
679
+ }
680
+ function increment(counts, key) {
681
+ counts.set(key, (counts.get(key) || 0) + 1);
682
+ }
683
+ function countOf(counts, key) {
684
+ if (!counts) {
685
+ return 0;
686
+ }
687
+ if (key !== undefined) {
688
+ return counts.get(key) || 0;
689
+ }
690
+ let total = 0;
691
+ for (const count of counts.values()) {
692
+ total += count;
693
+ }
694
+ return total;
695
+ }
696
+ // What went wrong with a message, for the server log.
697
+ function describeFailure(failure) {
698
+ if (failure instanceof HTTPErrorResponse) {
699
+ return `HTTP ${failure.statusCode}${failure.message ? `: ${failure.message}` : ""}`;
700
+ }
701
+ if (failure instanceof Error) {
702
+ return failure.message || failure.name;
703
+ }
704
+ return String(failure);
705
+ }
706
+ // "Site 03", "Site 03 and Site 07", "Site 03, Site 05 and Site 07", capped.
707
+ function joinNames(names) {
708
+ const listed = names.slice(0, MAX_LISTED_STATUS_MESSAGE_PAGES);
709
+ const more = names.length - listed.length;
710
+ if (more > 0) {
711
+ return `${listed.join(", ")} and ${more} more`;
712
+ }
713
+ if (listed.length <= 1) {
714
+ return listed.join("");
715
+ }
716
+ return `${listed.slice(0, -1).join(", ")} and ${listed[listed.length - 1]}`;
717
+ }
718
+ // A page name on one line, for the plain-text status message.
719
+ function toPlainText(text) {
720
+ return text.replace(/[\r\n]+/g, " ");
721
+ }
722
+ //# sourceMappingURL=SubscriberNotificationDeliveryRecord.js.map