@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
@@ -362,6 +362,11 @@ describe("StatusPageAPI manage-subscription link recipient", () => {
362
362
  .spyOn(StatusPageSubscriberService, "findBy")
363
363
  .mockImplementation(findByFake as never);
364
364
 
365
+ // Their unsubscribe tokens are topped up in the database; nothing to top up here.
366
+ jest
367
+ .spyOn(StatusPageSubscriberService, "ensureUnsubscribeTokens")
368
+ .mockResolvedValue(undefined as never);
369
+
365
370
  jest
366
371
  .spyOn(StatusPageSubscriberService, "getStatusPagesToSendNotification")
367
372
  .mockImplementation((): Promise<Array<StatusPage>> => {
@@ -610,8 +615,12 @@ describe("StatusPageAPI manage-subscription link recipient", () => {
610
615
  expect(lookup.query["statusPageId"]?.toString()).toBe(
611
616
  statusPageId.toString(),
612
617
  );
618
+ /*
619
+ * The contact for this channel only, and the unsubscribe token for the
620
+ * link that works without signing in.
621
+ */
613
622
  expect(Object.keys(lookup.select).sort()).toEqual(
614
- ["_id", "subscriberPhone"].sort(),
623
+ ["_id", "subscriberPhone", "unsubscribeToken"].sort(),
615
624
  );
616
625
  expect(lookup.sort).toEqual({ createdAt: SortOrder.Ascending });
617
626
  expect(lookup.skip).toBe(0);
@@ -99,6 +99,27 @@ const STATUS_PAGE_URL: string = "https://status.acme-example.com";
99
99
  const MANAGE_URL: string =
100
100
  "https://status.acme-example.com/update-subscription/c47d2e19-5b8a-4e36-a0f2-7d91b3c56e28";
101
101
 
102
+ /*
103
+ * The subscription's unsubscribe token, and the link that works without
104
+ * signing in - which the manage page on a private status page does not.
105
+ */
106
+ const UNSUBSCRIBE_TOKEN: string = "5d".repeat(32);
107
+ const UNSUBSCRIBE_URL: string = `https://status.acme-example.com/unsubscribe/c47d2e19-5b8a-4e36-a0f2-7d91b3c56e28-${UNSUBSCRIBE_TOKEN}`;
108
+
109
+ /*
110
+ * The unsubscribeUrl a channel's template is given. An SMS from a public
111
+ * status page gets the (shorter) manage link, as every other SMS from one
112
+ * does - an SMS is billed by the segment (see
113
+ * StatusPageSubscriberUnsubscribe.buildSmsLink); the fixture page is public.
114
+ */
115
+ function unsubscribeUrlOnPublicPage(
116
+ method: StatusPageSubscriberNotificationMethod,
117
+ ): string {
118
+ return method === StatusPageSubscriberNotificationMethod.SMS
119
+ ? MANAGE_URL
120
+ : UNSUBSCRIBE_URL;
121
+ }
122
+
102
123
  const SUBSCRIBER_EMAIL: string = "manage.subscriber@acme-example.com";
103
124
  const SUBSCRIBER_PHONE: string = "+15550100123";
104
125
  const SLACK_WORKSPACE_NAME: string = "acme-ops-workspace";
@@ -398,15 +419,45 @@ describe("StatusPageAPI manage-subscription templates", () => {
398
419
 
399
420
  type CompileCallsFunction = () => Array<CompileCall>;
400
421
 
422
+ /*
423
+ * Every compile, in the order it was made: the email body through
424
+ * compileEmailBodyTemplate (it is HTML, so its values are escaped), and
425
+ * the subject, SMS, Slack and Teams through compileTemplate.
426
+ */
401
427
  const compileCalls: CompileCallsFunction = (): Array<CompileCall> => {
402
- return mockOf(
428
+ const recorded: Array<{ order: number; call: CompileCall }> = [];
429
+
430
+ for (const compile of [
403
431
  StatusPageSubscriberNotificationTemplateServiceClass.compileTemplate,
404
- ).mock.calls.map((call: Array<unknown>): CompileCall => {
405
- return {
406
- template: call[0] as string,
407
- variables: call[1] as Record<string, string>,
408
- };
409
- });
432
+ StatusPageSubscriberNotificationTemplateServiceClass.compileEmailBodyTemplate,
433
+ ]) {
434
+ const calls: jest.MockContext<unknown, Array<unknown>> = mockOf(
435
+ compile,
436
+ ).mock;
437
+
438
+ calls.calls.forEach((call: Array<unknown>, index: number): void => {
439
+ recorded.push({
440
+ order: calls.invocationCallOrder[index]!,
441
+ call: {
442
+ template: call[0] as string,
443
+ variables: call[1] as Record<string, string>,
444
+ },
445
+ });
446
+ });
447
+ }
448
+
449
+ return recorded
450
+ .sort(
451
+ (
452
+ a: { order: number; call: CompileCall },
453
+ b: { order: number; call: CompileCall },
454
+ ): number => {
455
+ return a.order - b.order;
456
+ },
457
+ )
458
+ .map((entry: { order: number; call: CompileCall }): CompileCall => {
459
+ return entry.call;
460
+ });
410
461
  };
411
462
 
412
463
  type SentMailFunction = () => Array<JSONObject>;
@@ -486,6 +537,7 @@ describe("StatusPageAPI manage-subscription templates", () => {
486
537
 
487
538
  const subscriber: StatusPageSubscriber = new StatusPageSubscriber();
488
539
  subscriber.id = new ObjectID(SUBSCRIBER_ID);
540
+ subscriber.unsubscribeToken = UNSUBSCRIBE_TOKEN;
489
541
 
490
542
  if (query["subscriberEmail"]?.toString() === SUBSCRIBER_EMAIL) {
491
543
  subscriber.subscriberEmail = new Email(SUBSCRIBER_EMAIL);
@@ -569,8 +621,9 @@ describe("StatusPageAPI manage-subscription templates", () => {
569
621
  return Promise.resolve([pageToSend]);
570
622
  });
571
623
 
572
- // The real link builder, watched.
624
+ // The real link builders, watched.
573
625
  jest.spyOn(StatusPageSubscriberService, "getUnsubscribeLink");
626
+ jest.spyOn(StatusPageSubscriberService, "getManageSubscriptionLink");
574
627
 
575
628
  jest
576
629
  .spyOn(
@@ -584,6 +637,10 @@ describe("StatusPageAPI manage-subscription templates", () => {
584
637
  StatusPageSubscriberNotificationTemplateServiceClass,
585
638
  "compileTemplate",
586
639
  );
640
+ jest.spyOn(
641
+ StatusPageSubscriberNotificationTemplateServiceClass,
642
+ "compileEmailBodyTemplate",
643
+ );
587
644
 
588
645
  jest.spyOn(MailService, "sendMail").mockResolvedValue(undefined as never);
589
646
  jest.spyOn(SmsService, "sendSms").mockResolvedValue(undefined as never);
@@ -776,39 +833,134 @@ describe("StatusPageAPI manage-subscription templates", () => {
776
833
 
777
834
  describe("variable values", () => {
778
835
  it.each(CHANNELS)(
779
- "$name: unsubscribeUrl is the subscriber's manage link",
836
+ "$name: manageSubscriptionUrl is the manage page and unsubscribeUrl the token link",
780
837
  async (channel: ChannelCase) => {
781
838
  useCustomTemplatesOnEveryChannel();
782
839
 
783
840
  await callManageSubscription(channel.requestData);
784
841
 
785
- // Built by the real helper from the page URL and this subscriber.
842
+ // Built by the real helpers from the page URL and this subscriber.
843
+ const manageCalls: Array<Array<unknown>> = mockOf(
844
+ StatusPageSubscriberService.getManageSubscriptionLink,
845
+ ).mock.calls as Array<Array<unknown>>;
846
+ expect(manageCalls).toHaveLength(1);
847
+ expect((manageCalls[0]![0] as URL).toString()).toBe(
848
+ URL.fromString(STATUS_PAGE_URL).toString(),
849
+ );
850
+ expect((manageCalls[0]![1] as ObjectID).toString()).toBe(SUBSCRIBER_ID);
851
+
852
+ /*
853
+ * The unsubscribe link is built from the subscriber row the lookup
854
+ * read - token included - so it works without signing in.
855
+ */
786
856
  const linkCalls: Array<Array<unknown>> = mockOf(
787
857
  StatusPageSubscriberService.getUnsubscribeLink,
788
858
  ).mock.calls as Array<Array<unknown>>;
789
859
  expect(linkCalls).toHaveLength(1);
790
- expect((linkCalls[0]![0] as URL).toString()).toBe(
791
- URL.fromString(STATUS_PAGE_URL).toString(),
792
- );
793
- expect((linkCalls[0]![1] as ObjectID).toString()).toBe(SUBSCRIBER_ID);
860
+ expect(
861
+ (linkCalls[0]![1] as StatusPageSubscriber).unsubscribeToken,
862
+ ).toBe(UNSUBSCRIBE_TOKEN);
794
863
 
795
- expect(MANAGE_URL).not.toBe(STATUS_PAGE_URL);
796
864
  expect(MANAGE_URL).toContain(SUBSCRIBER_ID);
865
+ expect(UNSUBSCRIBE_URL).toContain(UNSUBSCRIBE_TOKEN);
797
866
 
798
867
  const calls: Array<CompileCall> = compileCalls();
799
868
  expect(calls).toHaveLength(channel.compileCallsPerRequest);
800
869
  for (const call of calls) {
801
- expect(call.variables["unsubscribeUrl"]).toBe(MANAGE_URL);
870
+ expect(call.variables["unsubscribeUrl"]).toBe(
871
+ unsubscribeUrlOnPublicPage(channel.method),
872
+ );
802
873
  expect(call.variables["manageSubscriptionUrl"]).toBe(MANAGE_URL);
803
874
  expect(call.variables["statusPageUrl"]).toBe(STATUS_PAGE_URL);
804
875
  }
805
876
 
806
877
  expect(renderedMessage(channel)).toContain(
807
- `unsubscribeUrl=[${MANAGE_URL}]`,
878
+ `unsubscribeUrl=[${unsubscribeUrlOnPublicPage(channel.method)}]`,
808
879
  );
809
880
  },
810
881
  );
811
882
 
883
+ it("sms from a private status page: unsubscribeUrl is the token link, since its manage page needs a signed-in visitor", async () => {
884
+ const smsChannel: ChannelCase = CHANNELS.find(
885
+ (channel: ChannelCase): boolean => {
886
+ return channel.method === StatusPageSubscriberNotificationMethod.SMS;
887
+ },
888
+ )!;
889
+
890
+ useCustomTemplatesOnEveryChannel();
891
+ pageToSend.isPublicStatusPage = false;
892
+
893
+ await callManageSubscription(smsChannel.requestData);
894
+
895
+ const calls: Array<CompileCall> = compileCalls();
896
+ expect(calls).toHaveLength(smsChannel.compileCallsPerRequest);
897
+ for (const call of calls) {
898
+ expect(call.variables["unsubscribeUrl"]).toBe(UNSUBSCRIBE_URL);
899
+ expect(call.variables["manageSubscriptionUrl"]).toBe(MANAGE_URL);
900
+ }
901
+ expect(renderedMessage(smsChannel)).toContain(
902
+ `unsubscribeUrl=[${UNSUBSCRIBE_URL}]`,
903
+ );
904
+ });
905
+
906
+ it("reads each subscriber's unsubscribe token with the lookup", async () => {
907
+ await callManageSubscription(CHANNELS[0]!.requestData);
908
+
909
+ const select: JSONObject = (
910
+ mockOf(StatusPageSubscriberService.findBy).mock.calls[0]![0] as {
911
+ select: JSONObject;
912
+ }
913
+ ).select;
914
+
915
+ expect(select["unsubscribeToken"]).toBe(true);
916
+ });
917
+
918
+ /*
919
+ * Every other sender tops up a missing token before building the link
920
+ * (ensureUnsubscribeTokens); a subscriber the backfill has not reached
921
+ * yet would otherwise be sent a link to the "out of date" page.
922
+ */
923
+ it("a subscriber read without its token is given one before the link is built", async () => {
924
+ const toppedUpToken: string = "9c".repeat(32);
925
+
926
+ jest
927
+ .spyOn(StatusPageSubscriberService, "findBy")
928
+ .mockImplementation((async (findBy: { query: JSONObject }) => {
929
+ const found: Array<StatusPageSubscriber> =
930
+ await findSubscribersFake(findBy);
931
+
932
+ for (const subscriber of found) {
933
+ subscriber.unsubscribeToken = undefined as unknown as string;
934
+ }
935
+
936
+ return found;
937
+ }) as never);
938
+
939
+ const ensure: jest.SpyInstance = jest
940
+ .spyOn(StatusPageSubscriberService, "ensureUnsubscribeTokens")
941
+ .mockImplementation((async (
942
+ subscribers: Array<StatusPageSubscriber>,
943
+ ): Promise<void> => {
944
+ for (const subscriber of subscribers) {
945
+ subscriber.unsubscribeToken = toppedUpToken;
946
+ }
947
+ }) as never);
948
+
949
+ useCustomTemplatesOnEveryChannel();
950
+
951
+ await callManageSubscription(CHANNELS[0]!.requestData);
952
+
953
+ expect(ensure).toHaveBeenCalledTimes(1);
954
+
955
+ const calls: Array<CompileCall> = compileCalls();
956
+ expect(calls.length).toBeGreaterThan(0);
957
+ for (const call of calls) {
958
+ expect(call.variables["unsubscribeUrl"]).toBe(
959
+ `${STATUS_PAGE_URL}/unsubscribe/${SUBSCRIBER_ID}-${toppedUpToken}`,
960
+ );
961
+ }
962
+ });
963
+
812
964
  it.each(CHANNELS)(
813
965
  "$name: statusPageName is the page's public title, not its internal name",
814
966
  async (channel: ChannelCase) => {
@@ -834,6 +986,42 @@ describe("StatusPageAPI manage-subscription templates", () => {
834
986
  },
835
987
  );
836
988
 
989
+ /*
990
+ * The email body is HTML, so the page's title - which a project member
991
+ * typed - is escaped into it and cannot add markup. SMS, Slack and Teams
992
+ * show text as written, and the subject is plain text, so they get it
993
+ * unchanged.
994
+ */
995
+ it.each(CHANNELS)(
996
+ "$name: a page title holding markup is escaped only in the email body",
997
+ async (channel: ChannelCase) => {
998
+ const hostileTitle: string =
999
+ '<a href="https://evil.example/login">Acme</a> & "Co"';
1000
+ useCustomTemplatesOnEveryChannel();
1001
+ pageToSend = statusPageFixture({
1002
+ withCustomSmtpAndSms: true,
1003
+ pageTitle: hostileTitle,
1004
+ });
1005
+
1006
+ await callManageSubscription(channel.requestData);
1007
+
1008
+ const message: string = renderedMessage(channel);
1009
+
1010
+ if (channel.method === StatusPageSubscriberNotificationMethod.Email) {
1011
+ expect(message).toContain(
1012
+ "statusPageName=[&lt;a href=&quot;https://evil.example/login&quot;&gt;Acme&lt;/a&gt; &amp; &quot;Co&quot;]",
1013
+ );
1014
+ expect(message).not.toContain("<a href");
1015
+ expect(sentMail()[0]!["subject"]).toBe(
1016
+ `Manage ${hostileTitle} at ${MANAGE_URL}`,
1017
+ );
1018
+ } else {
1019
+ expect(message).toContain(`statusPageName=[${hostileTitle}]`);
1020
+ expect(message).not.toMatch(/&(?:amp|lt|gt|quot|#39);/);
1021
+ }
1022
+ },
1023
+ );
1024
+
837
1025
  interface NameFallbackCase {
838
1026
  channel: ChannelCase;
839
1027
  label: string;
@@ -901,7 +1089,7 @@ describe("StatusPageAPI manage-subscription templates", () => {
901
1089
  const expectedValues: Record<string, string> = {
902
1090
  statusPageName: PAGE_TITLE,
903
1091
  statusPageUrl: STATUS_PAGE_URL,
904
- unsubscribeUrl: MANAGE_URL,
1092
+ unsubscribeUrl: unsubscribeUrlOnPublicPage(channel.method),
905
1093
  manageSubscriptionUrl: MANAGE_URL,
906
1094
  };
907
1095
 
@@ -86,6 +86,7 @@ function mockServices(data: { overview: boolean }): Fixtures {
86
86
  page.projectId = ObjectID.generate();
87
87
  page.isPublicStatusPage = true;
88
88
  page.showIncidentsOnStatusPage = true;
89
+ page.onlyShowScopedIncidents = false;
89
90
 
90
91
  const resource: StatusPageResource = new StatusPageResource();
91
92
  resource._id = ObjectID.generate().toString();
@@ -223,6 +224,15 @@ function mockServices(data: { overview: boolean }): Fixtures {
223
224
  return Promise.resolve([]);
224
225
  }
225
226
 
227
+ /*
228
+ * Each read is asked in two halves (IncidentStatusPageScope): incidents
229
+ * limited to no status page, which these all are, and incidents limited
230
+ * to this page, of which there are none.
231
+ */
232
+ if (query["isScopedToStatusPages"] !== false) {
233
+ return Promise.resolve([]);
234
+ }
235
+
226
236
  if (query["_id"]) {
227
237
  return Promise.resolve(
228
238
  incidents.filter((incident: Incident) => {
@@ -406,7 +416,8 @@ describe("StatusPageAPI postmortem visibility", () => {
406
416
  statusPageId: fixtures.statusPageId,
407
417
  });
408
418
 
409
- expect(fixtures.incidentReadSpy).toHaveBeenCalledTimes(2);
419
+ // Recent and active incidents, each read in two halves.
420
+ expect(fixtures.incidentReadSpy).toHaveBeenCalledTimes(2 * 2);
410
421
  expectVisibility({
411
422
  payload,
412
423
  key: "incidents",
@@ -433,7 +444,8 @@ describe("StatusPageAPI postmortem visibility", () => {
433
444
  incidentId: incident._id!,
434
445
  });
435
446
 
436
- expect(fixtures.incidentReadSpy).toHaveBeenCalledTimes(1);
447
+ // The one incident, read in two halves.
448
+ expect(fixtures.incidentReadSpy).toHaveBeenCalledTimes(2);
437
449
  expectVisibility({ payload, key: "incidents", incidents: [incident] });
438
450
  expectSourcesUnchanged(fixtures);
439
451
  },
@@ -0,0 +1,217 @@
1
+ import StatusPageSubscriber from "../../../Models/DatabaseModels/StatusPageSubscriber";
2
+ import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
3
+ import BaseAPI from "../../../Server/API/BaseAPI";
4
+ import DatabaseService from "../../../Server/Services/DatabaseService";
5
+ import ProjectService from "../../../Server/Services/ProjectService";
6
+ import StatusPageSubscriberService, {
7
+ Service as StatusPageSubscriberServiceClass,
8
+ } from "../../../Server/Services/StatusPageSubscriberService";
9
+ import {
10
+ RunOptions,
11
+ RunReturnType,
12
+ } from "../../../Server/Types/Workflow/ComponentCode";
13
+ import CreateManyBaseModel from "../../../Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel";
14
+ import CreateOneBaseModel from "../../../Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel";
15
+ import {
16
+ ExpressResponse,
17
+ OneUptimeRequest,
18
+ } from "../../../Server/Utils/Express";
19
+ import Response from "../../../Server/Utils/Response";
20
+ import Email from "../../../Types/Email";
21
+ import Exception from "../../../Types/Exception/Exception";
22
+ import { JSONArray, JSONObject } from "../../../Types/JSON";
23
+ import ObjectID from "../../../Types/ObjectID";
24
+ import UserType from "../../../Types/UserType";
25
+ import { mockRouter } from "./Helpers";
26
+ import {
27
+ afterEach,
28
+ beforeEach,
29
+ describe,
30
+ expect,
31
+ jest,
32
+ test,
33
+ } from "@jest/globals";
34
+
35
+ jest.mock("../../../Server/Utils/Express", () => {
36
+ return {
37
+ getRouter: () => {
38
+ return mockRouter;
39
+ },
40
+ };
41
+ });
42
+
43
+ jest.mock("../../../Server/Utils/Response", () => {
44
+ return {
45
+ sendEmptySuccessResponse: jest.fn(),
46
+ sendEntityResponse: jest.fn(),
47
+ sendEntityArrayResponse: jest.fn(),
48
+ sendJsonObjectResponse: jest.fn(),
49
+ };
50
+ });
51
+
52
+ /*
53
+ * A subscriber's create hands back the row it saved, and the unsubscribe
54
+ * token and the confirmation code are on that row: StatusPageSubscriberService
55
+ * minted them in onBeforeCreate. Nobody may read either column (read: []), but
56
+ * the create response of POST /status-page-subscriber is serialized whole,
57
+ * without a column read check - so a teammate's Add Subscriber or Add in Bulk,
58
+ * or any API key, got the token back, and could cancel the subscription
59
+ * "through the link", which the team's notice then blamed on the subscriber.
60
+ * A workflow's Create Status Page Subscriber step returned it too, and step
61
+ * return values are kept in the workflow's logs.
62
+ *
63
+ * DatabaseService.create is replaced with one that returns the saved row as
64
+ * the real one does, secrets and all; the service's own create is real.
65
+ */
66
+
67
+ const PROJECT_ID: ObjectID = new ObjectID(
68
+ "10000000-0000-4000-8000-000000000001",
69
+ );
70
+ const STATUS_PAGE_ID: ObjectID = new ObjectID(
71
+ "20000000-0000-4000-8000-000000000002",
72
+ );
73
+ const SUBSCRIBER_ID: string = "30000000-0000-4000-8000-000000000003";
74
+ const TOKEN: string = "4d".repeat(32);
75
+ const CONFIRMATION_CODE: string = "654321";
76
+
77
+ function savedRow(): StatusPageSubscriber {
78
+ const row: StatusPageSubscriber = new StatusPageSubscriber();
79
+ row._id = SUBSCRIBER_ID;
80
+ row.projectId = PROJECT_ID;
81
+ row.statusPageId = STATUS_PAGE_ID;
82
+ row.subscriberEmail = new Email("site03-all@acme.com");
83
+ row.isSubscriptionConfirmed = true;
84
+ row.isAddedByTeam = true;
85
+ row.unsubscribeToken = TOKEN;
86
+ row.subscriptionConfirmationToken = CONFIRMATION_CODE;
87
+ return row;
88
+ }
89
+
90
+ function expectNoSecrets(json: JSONObject): void {
91
+ const text: string = JSON.stringify(json);
92
+
93
+ expect(json["unsubscribeToken"]).toBeUndefined();
94
+ expect(json["subscriptionConfirmationToken"]).toBeUndefined();
95
+ expect(text).not.toContain(TOKEN);
96
+ expect(text).not.toContain(CONFIRMATION_CODE);
97
+
98
+ // The rest of the row is still there.
99
+ expect(json["_id"]).toBe(SUBSCRIBER_ID);
100
+ expect(JSON.stringify(json["subscriberEmail"])).toContain(
101
+ "site03-all@acme.com",
102
+ );
103
+ }
104
+
105
+ beforeEach(() => {
106
+ // With billing on, the request's props carry the project's plan.
107
+ jest
108
+ .spyOn(ProjectService, "getCurrentPlan")
109
+ .mockResolvedValue({ plan: null, isSubscriptionUnpaid: false } as never);
110
+
111
+ jest.spyOn(DatabaseService.prototype, "create").mockImplementation((() => {
112
+ return Promise.resolve(savedRow());
113
+ }) as never);
114
+ });
115
+
116
+ afterEach(() => {
117
+ jest.restoreAllMocks();
118
+ jest.clearAllMocks();
119
+ });
120
+
121
+ describe("POST /status-page-subscriber answers without the subscriber's secrets", () => {
122
+ function request(userType: UserType): OneUptimeRequest {
123
+ return {
124
+ params: {},
125
+ headers: {},
126
+ userType: userType,
127
+ tenantId: PROJECT_ID,
128
+ body: {
129
+ data: {
130
+ statusPageId: STATUS_PAGE_ID.toString(),
131
+ subscriberEmail: "site03-all@acme.com",
132
+ },
133
+ },
134
+ } as unknown as OneUptimeRequest;
135
+ }
136
+
137
+ test.each([
138
+ ["a teammate's Add Subscriber or Add in Bulk", UserType.User],
139
+ ["an API key", UserType.API],
140
+ ])("%s", async (_label: string, userType: UserType) => {
141
+ const api: BaseAPI<StatusPageSubscriber, StatusPageSubscriberServiceClass> =
142
+ new BaseAPI<StatusPageSubscriber, StatusPageSubscriberServiceClass>(
143
+ StatusPageSubscriber,
144
+ StatusPageSubscriberService,
145
+ );
146
+
147
+ await api.createItem(request(userType), {} as ExpressResponse);
148
+
149
+ const sendEntityResponse: jest.Mock =
150
+ Response.sendEntityResponse as unknown as jest.Mock;
151
+ expect(sendEntityResponse).toHaveBeenCalledTimes(1);
152
+
153
+ const item: StatusPageSubscriber = sendEntityResponse.mock
154
+ .calls[0]![2] as StatusPageSubscriber;
155
+
156
+ // What Response.sendEntityResponse serializes: every column that is set.
157
+ expectNoSecrets(BaseModel.toJSON(item, StatusPageSubscriber));
158
+ });
159
+ });
160
+
161
+ describe("a workflow's create steps return the subscriber without its secrets", () => {
162
+ function options(): RunOptions {
163
+ return {
164
+ log: jest.fn() as unknown as RunOptions["log"],
165
+ workflowLogId: ObjectID.generate(),
166
+ workflowId: ObjectID.generate(),
167
+ projectId: PROJECT_ID,
168
+ onError: ((exception: Exception): Exception => {
169
+ return exception;
170
+ }) as RunOptions["onError"],
171
+ executeWorkflow: async (): Promise<void> => {},
172
+ };
173
+ }
174
+
175
+ test("Create Status Page Subscriber", async () => {
176
+ const component: CreateOneBaseModel<StatusPageSubscriber> =
177
+ new CreateOneBaseModel<StatusPageSubscriber>(StatusPageSubscriberService);
178
+
179
+ const result: RunReturnType = await component.run(
180
+ {
181
+ json: {
182
+ statusPageId: STATUS_PAGE_ID.toString(),
183
+ subscriberEmail: "site03-all@acme.com",
184
+ },
185
+ },
186
+ options(),
187
+ );
188
+
189
+ expect(result.executePort?.id).toBe("success");
190
+ expectNoSecrets(result.returnValues["model"] as JSONObject);
191
+ });
192
+
193
+ test("Create Many Status Page Subscribers", async () => {
194
+ const component: CreateManyBaseModel<StatusPageSubscriber> =
195
+ new CreateManyBaseModel<StatusPageSubscriber>(
196
+ StatusPageSubscriberService,
197
+ );
198
+
199
+ const result: RunReturnType = await component.run(
200
+ {
201
+ "json-array": [
202
+ {
203
+ statusPageId: STATUS_PAGE_ID.toString(),
204
+ subscriberEmail: "site03-all@acme.com",
205
+ },
206
+ ],
207
+ },
208
+ options(),
209
+ );
210
+
211
+ expect(result.executePort?.id).toBe("success");
212
+
213
+ const models: JSONArray = result.returnValues["models"] as JSONArray;
214
+ expect(models).toHaveLength(1);
215
+ expectNoSecrets(models[0] as JSONObject);
216
+ });
217
+ });