@oneuptime/common 14.0.6 → 14.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (556) hide show
  1. package/Models/DatabaseModels/Incident.ts +267 -1
  2. package/Models/DatabaseModels/IncidentCustomField.ts +202 -0
  3. package/Models/DatabaseModels/IncidentEpisode.ts +30 -0
  4. package/Models/DatabaseModels/IncidentTemplate.ts +126 -1
  5. package/Models/DatabaseModels/InventoryItem.ts +23 -12
  6. package/Models/DatabaseModels/StatusPage.ts +55 -0
  7. package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
  8. package/Server/API/IncidentAPI.ts +162 -0
  9. package/Server/API/StatusPageAPI.ts +487 -171
  10. package/Server/API/StatusPageSubscriberAPI.ts +63 -15
  11. package/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.ts +217 -0
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
  20. package/Server/Infrastructure/Semaphore.ts +10 -0
  21. package/Server/Middleware/IdentityRateLimit.ts +108 -3
  22. package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
  23. package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
  24. package/Server/Services/AlertService.ts +32 -36
  25. package/Server/Services/DatabaseService.ts +93 -10
  26. package/Server/Services/IncidentAlertService.ts +609 -2
  27. package/Server/Services/IncidentCustomFieldService.ts +276 -1
  28. package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
  29. package/Server/Services/IncidentEpisodeService.ts +15 -0
  30. package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
  31. package/Server/Services/IncidentPublicNoteService.ts +30 -1
  32. package/Server/Services/IncidentService.ts +1663 -103
  33. package/Server/Services/IncidentStateTimelineService.ts +13 -0
  34. package/Server/Services/IncidentTemplateService.ts +109 -0
  35. package/Server/Services/InventoryItemService.ts +38 -0
  36. package/Server/Services/IoTDeviceCredentialService.ts +13 -4
  37. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
  38. package/Server/Services/ScheduledMaintenanceService.ts +118 -64
  39. package/Server/Services/SmsService.ts +10 -0
  40. package/Server/Services/StatusPageService.ts +65 -8
  41. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
  42. package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
  43. package/Server/Services/StatusPageSubscriberService.ts +1161 -64
  44. package/Server/Services/UserNotificationRuleService.ts +55 -53
  45. package/Server/Services/WorkspaceNotificationSummaryService.ts +38 -20
  46. package/Server/Types/Markdown.ts +153 -6
  47. package/Server/Types/Workflow/Components/Email.ts +61 -2
  48. package/Server/Utils/AffectedResources/LinkedAffectedResources.ts +576 -0
  49. package/Server/Utils/Alert/AlertStateChangeAuthorization.ts +129 -0
  50. package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
  51. package/Server/Utils/DataSource/EgressGuard.ts +66 -21
  52. package/Server/Utils/Inventory/InventoryOverviewAggregation.ts +111 -0
  53. package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
  54. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
  55. package/Server/Utils/Response.ts +31 -0
  56. package/Server/Utils/SSRFProtection.ts +76 -16
  57. package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
  58. package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
  59. package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
  60. package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
  61. package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
  62. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
  63. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
  64. package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
  65. package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
  66. package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
  67. package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
  68. package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
  69. package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
  70. package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
  71. package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
  72. package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
  73. package/Server/Utils/StatusPageResource.ts +51 -20
  74. package/Server/Utils/Topology/TopologyConcurrencyLimiter.ts +229 -0
  75. package/Server/Utils/Topology/TopologyQueries.ts +1350 -0
  76. package/Server/Utils/Topology/TopologyRequest.ts +463 -0
  77. package/Server/Utils/Topology/TopologyResponseCache.ts +183 -0
  78. package/Server/Utils/Topology/TopologySql.ts +1024 -0
  79. package/Server/Utils/VM/VMAPI.ts +1 -0
  80. package/Server/Utils/VM/VMRunner.ts +10 -0
  81. package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
  82. package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
  83. package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
  84. package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
  85. package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
  86. package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
  87. package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
  88. package/Tests/App/Dashboard/AcknowledgeAlertsOnDeclare.test.ts +369 -0
  89. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +1 -1
  90. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +510 -123
  91. package/Tests/App/Dashboard/AlertsTableAffectedResources.test.tsx +490 -0
  92. package/Tests/App/Dashboard/ChangeAlertStateDeclareIncident.test.tsx +886 -0
  93. package/Tests/App/Dashboard/CreateReviewStepRoleSummary.test.tsx +1250 -0
  94. package/Tests/App/Dashboard/CreateReviewStepSelectionSummary.test.tsx +738 -0
  95. package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
  96. package/Tests/App/Dashboard/DeclareIncidentFromAlert.test.ts +417 -0
  97. package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +1948 -229
  98. package/Tests/App/Dashboard/EntityDetailPanelLifecycle.test.tsx +493 -0
  99. package/Tests/App/Dashboard/EntityDetailPanelNavigation.test.tsx +439 -0
  100. package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
  101. package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
  102. package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
  103. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +534 -6
  104. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +798 -2
  105. package/Tests/App/Dashboard/FetchStateAndSeverityElements.test.tsx +669 -0
  106. package/Tests/App/Dashboard/FetchUsers.test.tsx +230 -0
  107. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
  108. package/Tests/App/Dashboard/IncidentCreateAcknowledgeAlerts.test.tsx +1611 -0
  109. package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
  110. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
  111. package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
  112. package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
  113. package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
  114. package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
  115. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
  116. package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
  117. package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
  118. package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
  119. package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
  120. package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +1365 -57
  121. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +964 -23
  122. package/Tests/App/Dashboard/InventoryRelationships.test.tsx +885 -0
  123. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
  124. package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +201 -15
  125. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +508 -36
  126. package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
  127. package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
  128. package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
  129. package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
  130. package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
  131. package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
  132. package/Tests/App/Dashboard/TopologyDataLifecycle.test.tsx +583 -0
  133. package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +982 -218
  134. package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +818 -114
  135. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
  136. package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
  137. package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
  138. package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
  139. package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
  140. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
  141. package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
  142. package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
  143. package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
  144. package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
  145. package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
  146. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
  147. package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
  148. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
  149. package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
  150. package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
  151. package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
  152. package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
  153. package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +90 -21
  154. package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
  155. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
  156. package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
  157. package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
  158. package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
  159. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
  160. package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
  161. package/Tests/Server/Services/DomainService.test.ts +525 -0
  162. package/Tests/Server/Services/IncidentAlertAcknowledgeOnDeclare.test.ts +2630 -0
  163. package/Tests/Server/Services/IncidentAlertPostgres.test.ts +1625 -1
  164. package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
  165. package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
  166. package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
  167. package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
  168. package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
  169. package/Tests/Server/Services/IncidentDeclareAcknowledgeAlerts.test.ts +2189 -0
  170. package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
  171. package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
  172. package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
  173. package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
  174. package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
  175. package/Tests/Server/Services/InventoryItemServiceOverviewCounts.test.ts +345 -0
  176. package/Tests/Server/Services/InventoryOverviewPostgres.test.ts +254 -0
  177. package/Tests/Server/Services/IoTDeviceCredentialService.test.ts +819 -0
  178. package/Tests/Server/Services/LinkedAffectedResourcesCreatedFeed.test.ts +420 -0
  179. package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
  180. package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
  181. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
  182. package/Tests/Server/Services/SloAffectedResourceCreatedFeed.test.ts +92 -36
  183. package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
  184. package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
  185. package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
  186. package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
  187. package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
  188. package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
  189. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
  190. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
  191. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
  192. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
  193. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
  194. package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
  195. package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
  196. package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
  197. package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
  198. package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
  199. package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
  200. package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
  201. package/Tests/Server/Utils/AffectedResources/LinkedAffectedResources.test.ts +858 -0
  202. package/Tests/Server/Utils/Alert/AlertStateChangeAuthorization.test.ts +1172 -0
  203. package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
  204. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
  205. package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
  206. package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
  207. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
  208. package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
  209. package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
  210. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
  211. package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
  212. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
  213. package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
  214. package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
  215. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
  216. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
  217. package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
  218. package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
  219. package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
  220. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
  221. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
  222. package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
  223. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
  224. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
  225. package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
  226. package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
  227. package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
  228. package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
  229. package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
  230. package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
  231. package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigration.test.ts +386 -0
  232. package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigrationPostgres.test.ts +430 -0
  233. package/Tests/Server/Utils/Topology/TopologyActivityParityPostgres.test.ts +279 -0
  234. package/Tests/Server/Utils/Topology/TopologyConcurrencyLimiter.test.ts +534 -0
  235. package/Tests/Server/Utils/Topology/TopologyEstateGenerator.ts +624 -0
  236. package/Tests/Server/Utils/Topology/TopologyJsonResponse.test.ts +90 -0
  237. package/Tests/Server/Utils/Topology/TopologyQueries.test.ts +1634 -0
  238. package/Tests/Server/Utils/Topology/TopologyQueriesDifferentialPostgres.test.ts +683 -0
  239. package/Tests/Server/Utils/Topology/TopologyQueriesPostgres.test.ts +2624 -0
  240. package/Tests/Server/Utils/Topology/TopologyReference.ts +1018 -0
  241. package/Tests/Server/Utils/Topology/TopologyRequest.test.ts +643 -0
  242. package/Tests/Server/Utils/Topology/TopologyResponseCache.test.ts +305 -0
  243. package/Tests/Server/Utils/Topology/TopologySql.test.ts +973 -0
  244. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
  245. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
  246. package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
  247. package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
  248. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
  249. package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
  250. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
  251. package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
  252. package/Tests/Types/SafeHtml.test.ts +102 -0
  253. package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
  254. package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
  255. package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
  256. package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
  257. package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
  258. package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
  259. package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
  260. package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
  261. package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
  262. package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
  263. package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
  264. package/Tests/Types/Topology/TopologyTypeRules.test.ts +176 -0
  265. package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
  266. package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
  267. package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
  268. package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
  269. package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
  270. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
  271. package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
  272. package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +302 -0
  273. package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
  274. package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
  275. package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
  276. package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
  277. package/Types/CustomField/CustomFieldOrder.ts +55 -0
  278. package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
  279. package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
  280. package/Types/CustomField/CustomFieldType.ts +14 -0
  281. package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
  282. package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
  283. package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
  284. package/Types/Incident/IncidentAlertLink.ts +19 -0
  285. package/Types/SafeHtml.ts +93 -0
  286. package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
  287. package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
  288. package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
  289. package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
  290. package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
  291. package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
  292. package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
  293. package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
  294. package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
  295. package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
  296. package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
  297. package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
  298. package/Types/Telemetry/InventoryLiveness.ts +26 -0
  299. package/Types/Topology/TopologyApi.ts +428 -0
  300. package/Types/Topology/TopologyTypeRules.ts +191 -0
  301. package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
  302. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
  303. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
  304. package/UI/Components/Forms/ModelForm.tsx +70 -8
  305. package/UI/Components/Forms/Validation.ts +1 -1
  306. package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
  307. package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
  308. package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
  309. package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
  310. package/UI/Components/ModelTable/ModelTable.tsx +6 -7
  311. package/UI/Utils/SensitiveUrlToken.ts +10 -5
  312. package/Utils/API.ts +247 -2
  313. package/Utils/Incident/IncidentFromAlerts.ts +78 -0
  314. package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
  315. package/Utils/Markdown/MarkdownEscape.ts +65 -0
  316. package/Utils/ProbeNetworkFailureUtil.ts +673 -0
  317. package/build/dist/Models/DatabaseModels/Incident.js +267 -1
  318. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  319. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
  320. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  321. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
  322. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  323. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
  324. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  325. package/build/dist/Models/DatabaseModels/InventoryItem.js +20 -11
  326. package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
  327. package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
  328. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  329. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
  330. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  331. package/build/dist/Server/API/IncidentAPI.js +100 -1
  332. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  333. package/build/dist/Server/API/StatusPageAPI.js +417 -176
  334. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  335. package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
  336. package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
  337. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js +165 -0
  338. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js.map +1 -0
  339. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
  340. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
  341. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
  342. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
  343. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
  344. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
  345. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
  346. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
  347. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
  348. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
  349. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
  350. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
  351. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
  352. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
  353. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
  354. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  355. package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
  356. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  357. package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
  358. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
  359. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
  360. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
  361. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
  362. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
  363. package/build/dist/Server/Services/AlertService.js +21 -33
  364. package/build/dist/Server/Services/AlertService.js.map +1 -1
  365. package/build/dist/Server/Services/DatabaseService.js +56 -7
  366. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  367. package/build/dist/Server/Services/IncidentAlertService.js +457 -3
  368. package/build/dist/Server/Services/IncidentAlertService.js.map +1 -1
  369. package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
  370. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  371. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
  372. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  373. package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
  374. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  375. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
  376. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  377. package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
  378. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  379. package/build/dist/Server/Services/IncidentService.js +1148 -42
  380. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  381. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  382. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  383. package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
  384. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  385. package/build/dist/Server/Services/InventoryItemService.js +31 -0
  386. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  387. package/build/dist/Server/Services/IoTDeviceCredentialService.js +12 -5
  388. package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -1
  389. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
  390. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  391. package/build/dist/Server/Services/ScheduledMaintenanceService.js +84 -57
  392. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  393. package/build/dist/Server/Services/SmsService.js +2 -22
  394. package/build/dist/Server/Services/SmsService.js.map +1 -1
  395. package/build/dist/Server/Services/StatusPageService.js +47 -9
  396. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  397. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
  398. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  399. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
  400. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
  401. package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
  402. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  403. package/build/dist/Server/Services/UserNotificationRuleService.js +55 -51
  404. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  405. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +42 -25
  406. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
  407. package/build/dist/Server/Types/Markdown.js +110 -6
  408. package/build/dist/Server/Types/Markdown.js.map +1 -1
  409. package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
  410. package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
  411. package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js +405 -0
  412. package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js.map +1 -0
  413. package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js +112 -0
  414. package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js.map +1 -0
  415. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
  416. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
  417. package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
  418. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  419. package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js +81 -0
  420. package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js.map +1 -0
  421. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
  422. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
  423. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
  424. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  425. package/build/dist/Server/Utils/Response.js +30 -0
  426. package/build/dist/Server/Utils/Response.js.map +1 -1
  427. package/build/dist/Server/Utils/SSRFProtection.js +48 -6
  428. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  429. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
  430. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
  431. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
  432. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
  433. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
  434. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
  435. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
  436. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
  437. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
  438. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
  439. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
  440. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
  441. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
  442. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
  443. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
  444. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
  445. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
  446. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
  447. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
  448. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
  449. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
  450. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
  451. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
  452. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
  453. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
  454. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
  455. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
  456. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
  457. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
  458. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
  459. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
  460. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
  461. package/build/dist/Server/Utils/StatusPageResource.js +39 -7
  462. package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
  463. package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js +178 -0
  464. package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js.map +1 -0
  465. package/build/dist/Server/Utils/Topology/TopologyQueries.js +884 -0
  466. package/build/dist/Server/Utils/Topology/TopologyQueries.js.map +1 -0
  467. package/build/dist/Server/Utils/Topology/TopologyRequest.js +275 -0
  468. package/build/dist/Server/Utils/Topology/TopologyRequest.js.map +1 -0
  469. package/build/dist/Server/Utils/Topology/TopologyResponseCache.js +146 -0
  470. package/build/dist/Server/Utils/Topology/TopologyResponseCache.js.map +1 -0
  471. package/build/dist/Server/Utils/Topology/TopologySql.js +688 -0
  472. package/build/dist/Server/Utils/Topology/TopologySql.js.map +1 -0
  473. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  474. package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
  475. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  476. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
  477. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
  478. package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
  479. package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
  480. package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
  481. package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
  482. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
  483. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
  484. package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
  485. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  486. package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
  487. package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
  488. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
  489. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
  490. package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
  491. package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
  492. package/build/dist/Types/Incident/IncidentAlertLink.js +17 -0
  493. package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -1
  494. package/build/dist/Types/SafeHtml.js +84 -0
  495. package/build/dist/Types/SafeHtml.js.map +1 -0
  496. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
  497. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
  498. package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
  499. package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
  500. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
  501. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
  502. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
  503. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
  504. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
  505. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
  506. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
  507. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
  508. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
  509. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
  510. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
  511. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
  512. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
  513. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
  514. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
  515. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
  516. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
  517. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
  518. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
  519. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
  520. package/build/dist/Types/Telemetry/InventoryLiveness.js +23 -0
  521. package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -1
  522. package/build/dist/Types/Topology/TopologyApi.js +55 -0
  523. package/build/dist/Types/Topology/TopologyApi.js.map +1 -0
  524. package/build/dist/Types/Topology/TopologyTypeRules.js +165 -0
  525. package/build/dist/Types/Topology/TopologyTypeRules.js.map +1 -0
  526. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
  527. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
  528. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
  529. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
  530. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
  531. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  532. package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
  533. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  534. package/build/dist/UI/Components/Forms/Validation.js +1 -1
  535. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  536. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  537. package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
  538. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
  539. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  540. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
  541. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  542. package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
  543. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  544. package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
  545. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
  546. package/build/dist/Utils/API.js +177 -1
  547. package/build/dist/Utils/API.js.map +1 -1
  548. package/build/dist/Utils/Incident/IncidentFromAlerts.js +38 -0
  549. package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -1
  550. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
  551. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
  552. package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
  553. package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
  554. package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
  555. package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
  556. package/package.json +1 -1
@@ -0,0 +1,1018 @@
1
+ import { JSONObject, JSONValue } from "../../../../Types/JSON";
2
+ import EntityRelationshipType from "../../../../Types/Telemetry/EntityRelationshipType";
3
+ import EntitySource from "../../../../Types/Telemetry/EntitySource";
4
+ import EntityType from "../../../../Types/Telemetry/EntityType";
5
+ import {
6
+ TOPOLOGY_API_FORMAT_VERSION,
7
+ TOPOLOGY_CONNECTION_SECTIONS,
8
+ TopologyApiLimits,
9
+ TopologyConnectionRowJSON,
10
+ TopologyConnectionSection,
11
+ TopologyConnectionSectionJSON,
12
+ TopologyDependencyJSON,
13
+ TopologyEntityDetailJSON,
14
+ TopologyEntityResponseJSON,
15
+ TopologyInfrastructureCollectionJSON,
16
+ TopologyInfrastructureDependencyJSON,
17
+ TopologyInfrastructureNodeJSON,
18
+ TopologyInfrastructureResponseJSON,
19
+ TopologyInfrastructureServiceJSON,
20
+ TopologyRunsOnCountJSON,
21
+ TopologyServiceMapEntityJSON,
22
+ TopologyServiceMapResponseJSON,
23
+ } from "../../../../Types/Topology/TopologyApi";
24
+ import {
25
+ CONTAINER_SPECIFICITY,
26
+ NESTABLE_CHILD_TYPES,
27
+ NESTING_RELATIONSHIP_PRIORITY,
28
+ PLACEMENT_RELATIONSHIP_TYPES,
29
+ SERVICE_MAP_DETAIL_ATTRIBUTE_KEYS,
30
+ isFlatInfrastructureType,
31
+ isTopologyInfrastructureType,
32
+ } from "../../../../Types/Topology/TopologyTypeRules";
33
+
34
+ /*
35
+ * A REFERENCE implementation of what the Topology API must return, written
36
+ * from the semantics the build spec lists (activity, item identity,
37
+ * relationships in range, nesting, placements, the Service Map payload and the
38
+ * drawer's sections) in plain TypeScript over whole rows.
39
+ *
40
+ * It deliberately shares nothing with the server's SQL (TopologySql /
41
+ * TopologyQueries): the differential tests compare the two, and the Dashboard
42
+ * parity test feeds this output through the real decoders to prove that the
43
+ * reduced payload rebuilds exactly the maps the old whole-inventory load gave.
44
+ * The only shared inputs are the contract types and the type rules in
45
+ * Common/Types/Topology, which are the specification both sides implement.
46
+ *
47
+ * Safety caps (TopologyApiLimits.Max*) are not modelled: the estates these
48
+ * tests generate stay far below them, so truncation is always null.
49
+ */
50
+
51
+ /* One InventoryItem row, every column the Topology API can read. */
52
+ export interface ReferenceItem {
53
+ /* `_id`, a lowercase UUID. */
54
+ id: string;
55
+ projectId: string;
56
+ key: string;
57
+ type: string;
58
+ name: string | null;
59
+ /* The column is NOT NULL; "" is a valid (blank) value. */
60
+ source: string;
61
+ lastSeenAt: Date | null;
62
+ firstSeenAt: Date | null;
63
+ createdAt: Date;
64
+ isArchived: boolean;
65
+ deleted: boolean;
66
+ /* Any JSON the jsonb column can hold (objects, arrays, scalars), or NULL. */
67
+ descriptiveAttributes: JSONValue | null;
68
+ identifyingAttributes: JSONValue | null;
69
+ resourceType: string | null;
70
+ resourceId: string | null;
71
+ }
72
+
73
+ /* One InventoryItemRelationship row. */
74
+ export interface ReferenceRelationship {
75
+ id: string;
76
+ projectId: string;
77
+ from: string;
78
+ to: string;
79
+ type: string;
80
+ lastSeenAt: Date | null;
81
+ createdAt: Date;
82
+ deleted: boolean;
83
+ callCount: number | null;
84
+ errorCount: number | null;
85
+ avgDurationMs: number | null;
86
+ }
87
+
88
+ export interface ReferenceEstate {
89
+ items: Array<ReferenceItem>;
90
+ relationships: Array<ReferenceRelationship>;
91
+ }
92
+
93
+ export interface ReferenceScope {
94
+ projectId: string;
95
+ /* Floored to the minute here, exactly as the server floors the request. */
96
+ rangeStart: Date;
97
+ }
98
+
99
+ export type ReferenceServiceMapResponse = Omit<
100
+ TopologyServiceMapResponseJSON,
101
+ "generatedAt"
102
+ >;
103
+
104
+ export type ReferenceInfrastructureResponse = Omit<
105
+ TopologyInfrastructureResponseJSON,
106
+ "generatedAt"
107
+ >;
108
+
109
+ export type ReferenceEntityResponse = Omit<
110
+ TopologyEntityResponseJSON,
111
+ "generatedAt"
112
+ >;
113
+
114
+ export interface ReferenceInfrastructureOptions {
115
+ /* Defaults to TopologyApiLimits.InlineFlatItemsPerType. */
116
+ inlineFlatItemsPerType?: number | undefined;
117
+ }
118
+
119
+ export interface ReferenceEntityRequest extends ReferenceScope {
120
+ entityKey: string;
121
+ entityType: string | null;
122
+ }
123
+
124
+ export interface ReferenceEntityOptions {
125
+ /*
126
+ * How the database's default collation orders drawer labels. Labels are
127
+ * the one place the server sorts by the database collation rather than by
128
+ * code points, so a caller that talks to a real database passes that
129
+ * database's order; the default is code-point order.
130
+ */
131
+ compareLabels?: ((left: string, right: string) => number) | undefined;
132
+ /* Relationships read at most (defaults to EntityConnectionScanLimit + 1). */
133
+ scanLimit?: number | undefined;
134
+ dependencyRows?: number | undefined;
135
+ otherRows?: number | undefined;
136
+ }
137
+
138
+ export const REFERENCE_UNNAMED_RESOURCE_LABEL: string = "Unnamed resource";
139
+ export const REFERENCE_UNDISCOVERED_RESOURCE_LABEL: string =
140
+ "Undiscovered resource";
141
+
142
+ // ------------------------------------------------------------ primitives
143
+
144
+ const MINUTE_MS: number = 60 * 1000;
145
+
146
+ export function floorToMinute(date: Date): Date {
147
+ return new Date(Math.floor(date.getTime() / MINUTE_MS) * MINUTE_MS);
148
+ }
149
+
150
+ /*
151
+ * COLLATE "C" on a UTF-8 database: byte order of the UTF-8 encoding, which is
152
+ * code-point order. That equals JavaScript's code-unit order everywhere
153
+ * except where a character outside the Basic Multilingual Plane (a surrogate
154
+ * pair in UTF-16) meets one in U+E000..U+FFFF, so the comparison is done on
155
+ * code points at the first difference.
156
+ */
157
+ export function compareCollateC(left: string, right: string): number {
158
+ if (left === right) {
159
+ return 0;
160
+ }
161
+ const length: number = Math.min(left.length, right.length);
162
+ let index: number = 0;
163
+ while (index < length && left.charCodeAt(index) === right.charCodeAt(index)) {
164
+ index++;
165
+ }
166
+ if (index === length) {
167
+ return left.length - right.length;
168
+ }
169
+ /* A difference in a low surrogate compares the whole pair. */
170
+ let start: number = index;
171
+ if (start > 0) {
172
+ const previous: number = left.charCodeAt(start - 1);
173
+ if (previous >= 0xd800 && previous <= 0xdbff) {
174
+ start--;
175
+ }
176
+ }
177
+ return left.codePointAt(start)! - right.codePointAt(start)!;
178
+ }
179
+
180
+ /* uuid columns compare as 16 raw bytes: the lowercase text's order. */
181
+ function compareIds(left: string, right: string): number {
182
+ const a: string = left.toLowerCase();
183
+ const b: string = right.toLowerCase();
184
+ if (a === b) {
185
+ return 0;
186
+ }
187
+ return a < b ? -1 : 1;
188
+ }
189
+
190
+ /* Semantics 1: the activity predicate. */
191
+ export function isReferenceActive(
192
+ row: { source: string | null; lastSeenAt: Date | null },
193
+ rangeStart: Date,
194
+ ): boolean {
195
+ if (
196
+ row.source !== null &&
197
+ row.source !== "" &&
198
+ row.source !== EntitySource.Discovered
199
+ ) {
200
+ return true;
201
+ }
202
+ if (row.lastSeenAt === null) {
203
+ return true;
204
+ }
205
+ return row.lastSeenAt.getTime() >= rangeStart.getTime();
206
+ }
207
+
208
+ /* Timestamps leave the server as floored epoch milliseconds. */
209
+ export function referenceEpochMs(date: Date | null): number | null {
210
+ return date === null ? null : Math.floor(date.getTime());
211
+ }
212
+
213
+ function isPlainObject(value: JSONValue | null | undefined): boolean {
214
+ return (
215
+ value !== null &&
216
+ value !== undefined &&
217
+ typeof value === "object" &&
218
+ !Array.isArray(value)
219
+ );
220
+ }
221
+
222
+ // -------------------------------------------------------------- snapshot
223
+
224
+ /* What every endpoint reads: the project's live items and in-range rows. */
225
+ interface ReferenceSnapshot {
226
+ rangeStart: Date;
227
+ /* Semantics 2: non-archived, non-deleted rows of the project. */
228
+ liveItems: Array<ReferenceItem>;
229
+ /* The winning live row of every key. */
230
+ winnerByKey: Map<string, ReferenceItem>;
231
+ /* Semantics 3: in-range, non-deleted relationships of the project. */
232
+ inRange: Array<ReferenceRelationship>;
233
+ }
234
+
235
+ /*
236
+ * Semantics 2: among live rows sharing a key the winner is the first by
237
+ * (createdAt ASC, _id DESC).
238
+ */
239
+ function compareWinner(left: ReferenceItem, right: ReferenceItem): number {
240
+ return (
241
+ left.createdAt.getTime() - right.createdAt.getTime() ||
242
+ compareIds(right.id, left.id)
243
+ );
244
+ }
245
+
246
+ function takeSnapshot(
247
+ estate: ReferenceEstate,
248
+ scope: ReferenceScope,
249
+ ): ReferenceSnapshot {
250
+ const rangeStart: Date = floorToMinute(scope.rangeStart);
251
+ const liveItems: Array<ReferenceItem> = estate.items.filter(
252
+ (item: ReferenceItem): boolean => {
253
+ return (
254
+ item.projectId === scope.projectId && !item.isArchived && !item.deleted
255
+ );
256
+ },
257
+ );
258
+ const winnerByKey: Map<string, ReferenceItem> = new Map<
259
+ string,
260
+ ReferenceItem
261
+ >();
262
+ for (const item of liveItems) {
263
+ const current: ReferenceItem | undefined = winnerByKey.get(item.key);
264
+ if (!current || compareWinner(item, current) < 0) {
265
+ winnerByKey.set(item.key, item);
266
+ }
267
+ }
268
+ const inRange: Array<ReferenceRelationship> = estate.relationships.filter(
269
+ (relationship: ReferenceRelationship): boolean => {
270
+ return (
271
+ relationship.projectId === scope.projectId &&
272
+ !relationship.deleted &&
273
+ relationship.lastSeenAt !== null &&
274
+ relationship.lastSeenAt.getTime() >= rangeStart.getTime()
275
+ );
276
+ },
277
+ );
278
+ return { rangeStart, liveItems, winnerByKey, inRange };
279
+ }
280
+
281
+ function winners(snapshot: ReferenceSnapshot): Array<ReferenceItem> {
282
+ return Array.from(snapshot.winnerByKey.values());
283
+ }
284
+
285
+ function byKeyC(left: ReferenceItem, right: ReferenceItem): number {
286
+ return compareCollateC(left.key, right.key);
287
+ }
288
+
289
+ function envelope(snapshot: ReferenceSnapshot): {
290
+ formatVersion: number;
291
+ rangeStart: string;
292
+ } {
293
+ return {
294
+ formatVersion: TOPOLOGY_API_FORMAT_VERSION,
295
+ rangeStart: snapshot.rangeStart.toISOString(),
296
+ };
297
+ }
298
+
299
+ // ----------------------------------------------------------- service map
300
+
301
+ /*
302
+ * Semantics 6: only the detail keys whose value is a JSON string, per bag;
303
+ * a bag with none of them is absent.
304
+ */
305
+ function detailBag(bag: JSONValue | null): Record<string, string> | undefined {
306
+ if (!isPlainObject(bag)) {
307
+ return undefined;
308
+ }
309
+ const object: JSONObject = bag as JSONObject;
310
+ const strings: Record<string, string> = {};
311
+ let count: number = 0;
312
+ for (const key of SERVICE_MAP_DETAIL_ATTRIBUTE_KEYS) {
313
+ const value: JSONValue | undefined = object[key];
314
+ if (typeof value === "string") {
315
+ strings[key] = value;
316
+ count++;
317
+ }
318
+ }
319
+ return count > 0 ? strings : undefined;
320
+ }
321
+
322
+ function toServiceMapEntity(item: ReferenceItem): TopologyServiceMapEntityJSON {
323
+ const entity: TopologyServiceMapEntityJSON = {
324
+ key: item.key,
325
+ type: item.type,
326
+ name: item.name,
327
+ source: item.source,
328
+ lastSeenAt: referenceEpochMs(item.lastSeenAt),
329
+ };
330
+ const descriptive: Record<string, string> | undefined = detailBag(
331
+ item.descriptiveAttributes,
332
+ );
333
+ const identifying: Record<string, string> | undefined = detailBag(
334
+ item.identifyingAttributes,
335
+ );
336
+ if (descriptive) {
337
+ entity.descriptiveAttributes = descriptive;
338
+ }
339
+ if (identifying) {
340
+ entity.identifyingAttributes = identifying;
341
+ }
342
+ return entity;
343
+ }
344
+
345
+ /* The old list API's order: createdAt DESC, _id ASC. */
346
+ function compareListOrder(
347
+ left: ReferenceRelationship,
348
+ right: ReferenceRelationship,
349
+ ): number {
350
+ return (
351
+ right.createdAt.getTime() - left.createdAt.getTime() ||
352
+ compareIds(left.id, right.id)
353
+ );
354
+ }
355
+
356
+ /*
357
+ * Semantics 5 / 6: distinct (service, target) pairs over in-range runs-on /
358
+ * hosted-on rows whose `from` is one of the given services.
359
+ */
360
+ function placementPairs(
361
+ snapshot: ReferenceSnapshot,
362
+ serviceKeys: Set<string>,
363
+ ): Array<[string, string]> {
364
+ const seen: Set<string> = new Set<string>();
365
+ const pairs: Array<[string, string]> = [];
366
+ for (const relationship of snapshot.inRange) {
367
+ if (
368
+ !PLACEMENT_RELATIONSHIP_TYPES.has(relationship.type) ||
369
+ !serviceKeys.has(relationship.from)
370
+ ) {
371
+ continue;
372
+ }
373
+ const id: string = `${relationship.from}\u0000${relationship.to}`;
374
+ if (seen.has(id)) {
375
+ continue;
376
+ }
377
+ seen.add(id);
378
+ pairs.push([relationship.from, relationship.to]);
379
+ }
380
+ return pairs;
381
+ }
382
+
383
+ export function referenceServiceMap(
384
+ estate: ReferenceEstate,
385
+ scope: ReferenceScope,
386
+ ): ReferenceServiceMapResponse {
387
+ const snapshot: ReferenceSnapshot = takeSnapshot(estate, scope);
388
+
389
+ /* Every live service, active or not. */
390
+ const services: Array<ReferenceItem> = winners(snapshot)
391
+ .filter((item: ReferenceItem): boolean => {
392
+ return item.type === EntityType.Service;
393
+ })
394
+ .sort(byKeyC);
395
+ const serviceKeys: Set<string> = new Set<string>(
396
+ services.map((item: ReferenceItem): string => {
397
+ return item.key;
398
+ }),
399
+ );
400
+
401
+ const dependencies: Array<TopologyDependencyJSON> = snapshot.inRange
402
+ .filter((relationship: ReferenceRelationship): boolean => {
403
+ return (
404
+ relationship.type === EntityRelationshipType.DependsOn &&
405
+ serviceKeys.has(relationship.from) &&
406
+ relationship.from !== relationship.to
407
+ );
408
+ })
409
+ .sort(compareListOrder)
410
+ .map((relationship: ReferenceRelationship): TopologyDependencyJSON => {
411
+ return {
412
+ from: relationship.from,
413
+ to: relationship.to,
414
+ callCount: relationship.callCount,
415
+ errorCount: relationship.errorCount,
416
+ avgDurationMs: relationship.avgDurationMs,
417
+ };
418
+ });
419
+
420
+ /*
421
+ * Callees: live items a dependency points at. A callee that is a service is
422
+ * already listed with the services.
423
+ */
424
+ const calleeKeys: Set<string> = new Set<string>(
425
+ dependencies.map((dependency: TopologyDependencyJSON): string => {
426
+ return dependency.to;
427
+ }),
428
+ );
429
+ const callees: Array<ReferenceItem> = winners(snapshot)
430
+ .filter((item: ReferenceItem): boolean => {
431
+ return calleeKeys.has(item.key) && !serviceKeys.has(item.key);
432
+ })
433
+ .sort(byKeyC);
434
+
435
+ /* Per (service, target type): distinct targets, and the active ones. */
436
+ const counts: Map<string, TopologyRunsOnCountJSON> = new Map<
437
+ string,
438
+ TopologyRunsOnCountJSON
439
+ >();
440
+ for (const [service, targetKey] of placementPairs(snapshot, serviceKeys)) {
441
+ const target: ReferenceItem | undefined =
442
+ snapshot.winnerByKey.get(targetKey);
443
+ if (!target) {
444
+ continue;
445
+ }
446
+ const id: string = `${service}\u0000${target.type}`;
447
+ let count: TopologyRunsOnCountJSON | undefined = counts.get(id);
448
+ if (!count) {
449
+ count = { service, type: target.type, active: 0, total: 0 };
450
+ counts.set(id, count);
451
+ }
452
+ count.total++;
453
+ if (isReferenceActive(target, snapshot.rangeStart)) {
454
+ count.active++;
455
+ }
456
+ }
457
+ const runsOn: Array<TopologyRunsOnCountJSON> = Array.from(
458
+ counts.values(),
459
+ ).sort(
460
+ (left: TopologyRunsOnCountJSON, right: TopologyRunsOnCountJSON): number => {
461
+ return (
462
+ compareCollateC(left.service, right.service) ||
463
+ compareCollateC(left.type, right.type)
464
+ );
465
+ },
466
+ );
467
+
468
+ if (services.length === 0) {
469
+ return {
470
+ ...envelope(snapshot),
471
+ entities: [],
472
+ dependencies: [],
473
+ runsOn: [],
474
+ entityTruncation: null,
475
+ dependencyTruncation: null,
476
+ };
477
+ }
478
+
479
+ return {
480
+ ...envelope(snapshot),
481
+ entities: [...services, ...callees].map(toServiceMapEntity),
482
+ dependencies,
483
+ runsOn,
484
+ entityTruncation: null,
485
+ dependencyTruncation: null,
486
+ };
487
+ }
488
+
489
+ // -------------------------------------------------------- infrastructure
490
+
491
+ interface NestingCandidate {
492
+ parent: ReferenceItem;
493
+ via: string;
494
+ priority: number;
495
+ specificity: number;
496
+ }
497
+
498
+ /* Semantics 4: priority DESC, specificity DESC, parent key (C) ASC. */
499
+ function compareCandidates(
500
+ left: NestingCandidate,
501
+ right: NestingCandidate,
502
+ ): number {
503
+ return (
504
+ right.priority - left.priority ||
505
+ right.specificity - left.specificity ||
506
+ compareCollateC(left.parent.key, right.parent.key)
507
+ );
508
+ }
509
+
510
+ function best(
511
+ candidates: Array<NestingCandidate>,
512
+ ): NestingCandidate | undefined {
513
+ let winner: NestingCandidate | undefined = undefined;
514
+ for (const candidate of candidates) {
515
+ if (!winner || compareCandidates(candidate, winner) < 0) {
516
+ winner = candidate;
517
+ }
518
+ }
519
+ return winner;
520
+ }
521
+
522
+ function maxDate(dates: Array<Date | null>): Date | null {
523
+ let latest: Date | null = null;
524
+ for (const date of dates) {
525
+ if (date && (!latest || date.getTime() > latest.getTime())) {
526
+ latest = date;
527
+ }
528
+ }
529
+ return latest;
530
+ }
531
+
532
+ export function referenceInfrastructure(
533
+ estate: ReferenceEstate,
534
+ scope: ReferenceScope,
535
+ options: ReferenceInfrastructureOptions = {},
536
+ ): ReferenceInfrastructureResponse {
537
+ const snapshot: ReferenceSnapshot = takeSnapshot(estate, scope);
538
+ const inlineBudget: number =
539
+ options.inlineFlatItemsPerType ?? TopologyApiLimits.InlineFlatItemsPerType;
540
+ const rangeStart: Date = snapshot.rangeStart;
541
+
542
+ /*
543
+ * Collections: a flat type with more live ROWS than the inline budget.
544
+ * Counted over rows (the collection's pages list rows of the type), with
545
+ * the latest report over all of them and over the active ones.
546
+ */
547
+ const rowsByType: Map<string, Array<ReferenceItem>> = new Map<
548
+ string,
549
+ Array<ReferenceItem>
550
+ >();
551
+ for (const item of snapshot.liveItems) {
552
+ if (!isTopologyInfrastructureType(item.type)) {
553
+ continue;
554
+ }
555
+ const rows: Array<ReferenceItem> = rowsByType.get(item.type) || [];
556
+ rows.push(item);
557
+ rowsByType.set(item.type, rows);
558
+ }
559
+ const collections: Array<TopologyInfrastructureCollectionJSON> = [];
560
+ const collectedTypes: Set<string> = new Set<string>();
561
+ for (const type of Array.from(rowsByType.keys()).sort(compareCollateC)) {
562
+ const rows: Array<ReferenceItem> = rowsByType.get(type)!;
563
+ if (!isFlatInfrastructureType(type) || rows.length <= inlineBudget) {
564
+ continue;
565
+ }
566
+ const active: Array<ReferenceItem> = rows.filter(
567
+ (item: ReferenceItem): boolean => {
568
+ return isReferenceActive(item, rangeStart);
569
+ },
570
+ );
571
+ collectedTypes.add(type);
572
+ collections.push({
573
+ type,
574
+ total: rows.length,
575
+ active: active.length,
576
+ lastSeenAt: referenceEpochMs(
577
+ maxDate(
578
+ rows.map((item: ReferenceItem): Date | null => {
579
+ return item.lastSeenAt;
580
+ }),
581
+ ),
582
+ ),
583
+ activeLastSeenAt: referenceEpochMs(
584
+ maxDate(
585
+ active.map((item: ReferenceItem): Date | null => {
586
+ return item.lastSeenAt;
587
+ }),
588
+ ),
589
+ ),
590
+ });
591
+ }
592
+
593
+ /* Semantics 4: the node set, ordered by (type, key) in code points. */
594
+ const nodes: Array<ReferenceItem> = winners(snapshot)
595
+ .filter((item: ReferenceItem): boolean => {
596
+ return (
597
+ isTopologyInfrastructureType(item.type) &&
598
+ !collectedTypes.has(item.type)
599
+ );
600
+ })
601
+ .sort((left: ReferenceItem, right: ReferenceItem): number => {
602
+ return compareCollateC(left.type, right.type) || byKeyC(left, right);
603
+ });
604
+ const nodeIndexByKey: Map<string, number> = new Map<string, number>();
605
+ nodes.forEach((node: ReferenceItem, index: number): void => {
606
+ nodeIndexByKey.set(node.key, index);
607
+ });
608
+
609
+ const candidatesByChild: Map<string, Array<NestingCandidate>> = new Map<
610
+ string,
611
+ Array<NestingCandidate>
612
+ >();
613
+ for (const relationship of snapshot.inRange) {
614
+ const priority: number | undefined =
615
+ NESTING_RELATIONSHIP_PRIORITY[
616
+ relationship.type as EntityRelationshipType
617
+ ];
618
+ if (priority === undefined || relationship.from === relationship.to) {
619
+ continue;
620
+ }
621
+ const childIndex: number | undefined = nodeIndexByKey.get(
622
+ relationship.from,
623
+ );
624
+ const parentIndex: number | undefined = nodeIndexByKey.get(relationship.to);
625
+ if (childIndex === undefined || parentIndex === undefined) {
626
+ continue;
627
+ }
628
+ const child: ReferenceItem = nodes[childIndex]!;
629
+ const parent: ReferenceItem = nodes[parentIndex]!;
630
+ const specificity: number | undefined =
631
+ CONTAINER_SPECIFICITY[parent.type as EntityType];
632
+ if (
633
+ !NESTABLE_CHILD_TYPES.has(child.type as EntityType) ||
634
+ specificity === undefined
635
+ ) {
636
+ continue;
637
+ }
638
+ const candidates: Array<NestingCandidate> =
639
+ candidatesByChild.get(child.key) || [];
640
+ candidates.push({
641
+ parent,
642
+ via: relationship.type,
643
+ priority,
644
+ specificity,
645
+ });
646
+ candidatesByChild.set(child.key, candidates);
647
+ }
648
+
649
+ let activeResources: number = 0;
650
+ const nodeRows: Array<TopologyInfrastructureNodeJSON> = nodes.map(
651
+ (node: ReferenceItem): TopologyInfrastructureNodeJSON => {
652
+ if (isReferenceActive(node, rangeStart)) {
653
+ activeResources++;
654
+ }
655
+ const row: TopologyInfrastructureNodeJSON = {
656
+ key: node.key,
657
+ type: node.type,
658
+ name: node.name,
659
+ source: node.source,
660
+ lastSeenAt: referenceEpochMs(node.lastSeenAt),
661
+ };
662
+ const candidates: Array<NestingCandidate> =
663
+ candidatesByChild.get(node.key) || [];
664
+ const parent: NestingCandidate | undefined = best(candidates);
665
+ if (!parent) {
666
+ return row;
667
+ }
668
+ row.parent = nodeIndexByKey.get(parent.parent.key)!;
669
+ row.parentVia = parent.via;
670
+ if (!isReferenceActive(parent.parent, rangeStart)) {
671
+ const activeParent: NestingCandidate | undefined = best(
672
+ candidates.filter((candidate: NestingCandidate): boolean => {
673
+ return isReferenceActive(candidate.parent, rangeStart);
674
+ }),
675
+ );
676
+ if (activeParent) {
677
+ row.activeParent = nodeIndexByKey.get(activeParent.parent.key)!;
678
+ row.activeParentVia = activeParent.via;
679
+ } else {
680
+ row.activeParent = -1;
681
+ }
682
+ }
683
+ return row;
684
+ },
685
+ );
686
+
687
+ const services: Array<ReferenceItem> = winners(snapshot)
688
+ .filter((item: ReferenceItem): boolean => {
689
+ return item.type === EntityType.Service;
690
+ })
691
+ .sort(byKeyC);
692
+ const serviceIndexByKey: Map<string, number> = new Map<string, number>();
693
+ services.forEach((service: ReferenceItem, index: number): void => {
694
+ serviceIndexByKey.set(service.key, index);
695
+ });
696
+
697
+ const placements: Array<[number, number]> = [];
698
+ for (const [service, target] of placementPairs(
699
+ snapshot,
700
+ new Set<string>(serviceIndexByKey.keys()),
701
+ )) {
702
+ const nodeIndex: number | undefined = nodeIndexByKey.get(target);
703
+ if (nodeIndex !== undefined) {
704
+ placements.push([serviceIndexByKey.get(service)!, nodeIndex]);
705
+ }
706
+ }
707
+ placements.sort((left: [number, number], right: [number, number]): number => {
708
+ return left[0] - right[0] || left[1] - right[1];
709
+ });
710
+
711
+ /*
712
+ * Infrastructure traffic: in-range calls between two different services that each
713
+ * have a placement onto a shipped node, by service index, ordered by
714
+ * (from, to). A pair is at most one row (the relationship natural key).
715
+ */
716
+ const placedServiceKeys: Set<string> = new Set<string>(
717
+ placements.map((placement: [number, number]): string => {
718
+ return services[placement[0]]!.key;
719
+ }),
720
+ );
721
+ const dependencies: Array<TopologyInfrastructureDependencyJSON> =
722
+ snapshot.inRange
723
+ .filter((relationship: ReferenceRelationship): boolean => {
724
+ return (
725
+ relationship.type === EntityRelationshipType.DependsOn &&
726
+ relationship.from !== relationship.to &&
727
+ placedServiceKeys.has(relationship.from) &&
728
+ placedServiceKeys.has(relationship.to)
729
+ );
730
+ })
731
+ .map(
732
+ (
733
+ relationship: ReferenceRelationship,
734
+ ): TopologyInfrastructureDependencyJSON => {
735
+ return {
736
+ from: serviceIndexByKey.get(relationship.from)!,
737
+ to: serviceIndexByKey.get(relationship.to)!,
738
+ callCount: relationship.callCount,
739
+ errorCount: relationship.errorCount,
740
+ avgDurationMs: relationship.avgDurationMs,
741
+ };
742
+ },
743
+ )
744
+ .sort(
745
+ (
746
+ left: TopologyInfrastructureDependencyJSON,
747
+ right: TopologyInfrastructureDependencyJSON,
748
+ ): number => {
749
+ return left.from - right.from || left.to - right.to;
750
+ },
751
+ );
752
+
753
+ let resources: number = nodes.length;
754
+ for (const collection of collections) {
755
+ resources += collection.total;
756
+ activeResources += collection.active;
757
+ }
758
+
759
+ return {
760
+ ...envelope(snapshot),
761
+ nodes: nodeRows,
762
+ services: services.map(
763
+ (service: ReferenceItem): TopologyInfrastructureServiceJSON => {
764
+ return { key: service.key, name: service.name };
765
+ },
766
+ ),
767
+ placements,
768
+ dependencies,
769
+ dependencyTruncation: null,
770
+ collections,
771
+ totals: { resources, activeResources },
772
+ truncation: null,
773
+ };
774
+ }
775
+
776
+ // ---------------------------------------------------------------- drawer
777
+
778
+ interface ClassifiedConnection {
779
+ section: TopologyConnectionSection;
780
+ label: string;
781
+ row: TopologyConnectionRowJSON;
782
+ }
783
+
784
+ function compareScanOrder(
785
+ left: ReferenceRelationship,
786
+ right: ReferenceRelationship,
787
+ ): number {
788
+ return (
789
+ right.lastSeenAt!.getTime() - left.lastSeenAt!.getTime() ||
790
+ compareIds(left.id, right.id)
791
+ );
792
+ }
793
+
794
+ function emptySection(): TopologyConnectionSectionJSON {
795
+ return { total: 0, unknownTotal: 0, rows: [], nextOffset: null };
796
+ }
797
+
798
+ function emptySections(): Record<
799
+ TopologyConnectionSection,
800
+ TopologyConnectionSectionJSON
801
+ > {
802
+ return {
803
+ calls: emptySection(),
804
+ calledBy: emptySection(),
805
+ runsOn: emptySection(),
806
+ related: emptySection(),
807
+ };
808
+ }
809
+
810
+ function detailObject(value: JSONValue | null): JSONObject | null {
811
+ return isPlainObject(value) ? (value as JSONObject) : null;
812
+ }
813
+
814
+ /*
815
+ * The drawer (semantics 8): the entity's full row and its in-range
816
+ * relationships in four sections with exact totals and the top rows.
817
+ */
818
+ export function referenceEntity(
819
+ estate: ReferenceEstate,
820
+ request: ReferenceEntityRequest,
821
+ options: ReferenceEntityOptions = {},
822
+ ): ReferenceEntityResponse {
823
+ const snapshot: ReferenceSnapshot = takeSnapshot(estate, request);
824
+ const compareLabels: (left: string, right: string) => number =
825
+ options.compareLabels || compareCollateC;
826
+ const scanLimit: number =
827
+ options.scanLimit ?? TopologyApiLimits.EntityConnectionScanLimit + 1;
828
+ const dependencyRows: number =
829
+ options.dependencyRows ?? TopologyApiLimits.EntityDependencyRows;
830
+ const otherRows: number =
831
+ options.otherRows ?? TopologyApiLimits.EntityOtherRows;
832
+
833
+ /*
834
+ * The key's live rows; a known type narrows the choice, then the winner
835
+ * rule decides.
836
+ */
837
+ const rows: Array<ReferenceItem> = snapshot.liveItems
838
+ .filter((item: ReferenceItem): boolean => {
839
+ return item.key === request.entityKey;
840
+ })
841
+ .sort((left: ReferenceItem, right: ReferenceItem): number => {
842
+ const leftRank: number =
843
+ request.entityType !== null && left.type === request.entityType ? 0 : 1;
844
+ const rightRank: number =
845
+ request.entityType !== null && right.type === request.entityType
846
+ ? 0
847
+ : 1;
848
+ return leftRank - rightRank || compareWinner(left, right);
849
+ });
850
+ const item: ReferenceItem | undefined = rows[0];
851
+ if (!item) {
852
+ return {
853
+ ...envelope(snapshot),
854
+ entity: null,
855
+ sections: emptySections(),
856
+ isScanLimited: false,
857
+ };
858
+ }
859
+
860
+ const entity: TopologyEntityDetailJSON = {
861
+ key: item.key,
862
+ type: item.type,
863
+ name: item.name,
864
+ source: item.source,
865
+ lastSeenAt: referenceEpochMs(item.lastSeenAt),
866
+ id: item.id,
867
+ firstSeenAt: referenceEpochMs(item.firstSeenAt),
868
+ resourceType: item.resourceType,
869
+ resourceId: item.resourceId,
870
+ identifyingAttributes: detailObject(item.identifyingAttributes),
871
+ descriptiveAttributes: detailObject(item.descriptiveAttributes),
872
+ };
873
+
874
+ /* Outbound first, then inbound (self-loops once, as outbound). */
875
+ const outbound: Array<ReferenceRelationship> = snapshot.inRange
876
+ .filter((relationship: ReferenceRelationship): boolean => {
877
+ return relationship.from === item.key;
878
+ })
879
+ .sort(compareScanOrder)
880
+ .slice(0, scanLimit);
881
+ const inbound: Array<ReferenceRelationship> = snapshot.inRange
882
+ .filter((relationship: ReferenceRelationship): boolean => {
883
+ return relationship.to === item.key && relationship.from !== item.key;
884
+ })
885
+ .sort(compareScanOrder)
886
+ .slice(0, Math.max(0, scanLimit - outbound.length));
887
+
888
+ const isService: boolean = item.type === EntityType.Service;
889
+ const classified: Array<ClassifiedConnection> = [];
890
+ const scanned: Array<[ReferenceRelationship, "out" | "in"]> = [
891
+ ...outbound.map(
892
+ (
893
+ relationship: ReferenceRelationship,
894
+ ): [ReferenceRelationship, "out" | "in"] => {
895
+ return [relationship, "out"];
896
+ },
897
+ ),
898
+ ...inbound.map(
899
+ (
900
+ relationship: ReferenceRelationship,
901
+ ): [ReferenceRelationship, "out" | "in"] => {
902
+ return [relationship, "in"];
903
+ },
904
+ ),
905
+ ];
906
+ for (const [relationship, direction] of scanned) {
907
+ const otherKey: string =
908
+ direction === "out" ? relationship.to : relationship.from;
909
+ const other: ReferenceItem | undefined = snapshot.winnerByKey.get(otherKey);
910
+ let section: TopologyConnectionSection = "related";
911
+ if (relationship.type === EntityRelationshipType.DependsOn) {
912
+ section = direction === "out" ? "calls" : "calledBy";
913
+ } else if (
914
+ direction === "out" &&
915
+ isService &&
916
+ PLACEMENT_RELATIONSHIP_TYPES.has(relationship.type)
917
+ ) {
918
+ section = "runsOn";
919
+ }
920
+ const label: string =
921
+ other && other.name
922
+ ? other.name
923
+ : other
924
+ ? REFERENCE_UNNAMED_RESOURCE_LABEL
925
+ : REFERENCE_UNDISCOVERED_RESOURCE_LABEL;
926
+ classified.push({
927
+ section,
928
+ label,
929
+ row: {
930
+ relationshipType: relationship.type,
931
+ direction,
932
+ otherKey,
933
+ otherKnown: Boolean(other),
934
+ otherName: other ? other.name : null,
935
+ otherType: other ? other.type : null,
936
+ callCount: relationship.callCount,
937
+ errorCount: relationship.errorCount,
938
+ avgDurationMs: relationship.avgDurationMs,
939
+ lastSeenAt: referenceEpochMs(relationship.lastSeenAt),
940
+ },
941
+ });
942
+ }
943
+
944
+ /*
945
+ * calls / calledBy: callCount DESC NULLS LAST; runsOn / related: known
946
+ * first. Then label, other key (C), and — for rows that still tie (one
947
+ * other end reached by several relationship types or both directions) —
948
+ * relationship type (C) and direction.
949
+ */
950
+ const compareRows: (
951
+ left: ClassifiedConnection,
952
+ right: ClassifiedConnection,
953
+ ) => number = (
954
+ left: ClassifiedConnection,
955
+ right: ClassifiedConnection,
956
+ ): number => {
957
+ let primary: number = 0;
958
+ if (left.section === "calls" || left.section === "calledBy") {
959
+ const a: number | null = left.row.callCount;
960
+ const b: number | null = right.row.callCount;
961
+ if (a === null || b === null) {
962
+ primary = (a === null ? 1 : 0) - (b === null ? 1 : 0);
963
+ } else {
964
+ primary = b - a;
965
+ }
966
+ } else {
967
+ primary = Number(right.row.otherKnown) - Number(left.row.otherKnown);
968
+ }
969
+ return (
970
+ primary ||
971
+ compareLabels(left.label, right.label) ||
972
+ compareCollateC(left.row.otherKey, right.row.otherKey) ||
973
+ compareCollateC(left.row.relationshipType, right.row.relationshipType) ||
974
+ compareCollateC(left.row.direction, right.row.direction)
975
+ );
976
+ };
977
+
978
+ const sections: Record<
979
+ TopologyConnectionSection,
980
+ TopologyConnectionSectionJSON
981
+ > = emptySections();
982
+ for (const section of TOPOLOGY_CONNECTION_SECTIONS) {
983
+ const members: Array<ClassifiedConnection> = classified
984
+ .filter((connection: ClassifiedConnection): boolean => {
985
+ return connection.section === section;
986
+ })
987
+ .sort(compareRows);
988
+ const budget: number =
989
+ section === "calls" || section === "calledBy"
990
+ ? dependencyRows
991
+ : otherRows;
992
+ const shown: Array<TopologyConnectionRowJSON> = members
993
+ .slice(0, budget)
994
+ .map((connection: ClassifiedConnection): TopologyConnectionRowJSON => {
995
+ return connection.row;
996
+ });
997
+ sections[section] = {
998
+ total: members.length,
999
+ unknownTotal: members.filter(
1000
+ (connection: ClassifiedConnection): boolean => {
1001
+ return !connection.row.otherKnown;
1002
+ },
1003
+ ).length,
1004
+ rows: shown,
1005
+ nextOffset:
1006
+ shown.length > 0 && shown.length < members.length ? shown.length : null,
1007
+ };
1008
+ }
1009
+
1010
+ return {
1011
+ ...envelope(snapshot),
1012
+ entity,
1013
+ sections,
1014
+ isScanLimited:
1015
+ outbound.length + inbound.length >
1016
+ TopologyApiLimits.EntityConnectionScanLimit,
1017
+ };
1018
+ }