@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.
- package/Models/DatabaseModels/Incident.ts +267 -1
- package/Models/DatabaseModels/IncidentCustomField.ts +202 -0
- package/Models/DatabaseModels/IncidentEpisode.ts +30 -0
- package/Models/DatabaseModels/IncidentTemplate.ts +126 -1
- package/Models/DatabaseModels/InventoryItem.ts +23 -12
- package/Models/DatabaseModels/StatusPage.ts +55 -0
- package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
- package/Server/API/IncidentAPI.ts +162 -0
- package/Server/API/StatusPageAPI.ts +487 -171
- package/Server/API/StatusPageSubscriberAPI.ts +63 -15
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.ts +217 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
- package/Server/Infrastructure/Semaphore.ts +10 -0
- package/Server/Middleware/IdentityRateLimit.ts +108 -3
- package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
- package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
- package/Server/Services/AlertService.ts +32 -36
- package/Server/Services/DatabaseService.ts +93 -10
- package/Server/Services/IncidentAlertService.ts +609 -2
- package/Server/Services/IncidentCustomFieldService.ts +276 -1
- package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
- package/Server/Services/IncidentEpisodeService.ts +15 -0
- package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
- package/Server/Services/IncidentPublicNoteService.ts +30 -1
- package/Server/Services/IncidentService.ts +1663 -103
- package/Server/Services/IncidentStateTimelineService.ts +13 -0
- package/Server/Services/IncidentTemplateService.ts +109 -0
- package/Server/Services/InventoryItemService.ts +38 -0
- package/Server/Services/IoTDeviceCredentialService.ts +13 -4
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
- package/Server/Services/ScheduledMaintenanceService.ts +118 -64
- package/Server/Services/SmsService.ts +10 -0
- package/Server/Services/StatusPageService.ts +65 -8
- package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
- package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
- package/Server/Services/StatusPageSubscriberService.ts +1161 -64
- package/Server/Services/UserNotificationRuleService.ts +55 -53
- package/Server/Services/WorkspaceNotificationSummaryService.ts +38 -20
- package/Server/Types/Markdown.ts +153 -6
- package/Server/Types/Workflow/Components/Email.ts +61 -2
- package/Server/Utils/AffectedResources/LinkedAffectedResources.ts +576 -0
- package/Server/Utils/Alert/AlertStateChangeAuthorization.ts +129 -0
- package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
- package/Server/Utils/DataSource/EgressGuard.ts +66 -21
- package/Server/Utils/Inventory/InventoryOverviewAggregation.ts +111 -0
- package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
- package/Server/Utils/Response.ts +31 -0
- package/Server/Utils/SSRFProtection.ts +76 -16
- package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
- package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
- package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
- package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
- package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
- package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
- package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
- package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
- package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
- package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
- package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
- package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
- package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
- package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
- package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
- package/Server/Utils/StatusPageResource.ts +51 -20
- package/Server/Utils/Topology/TopologyConcurrencyLimiter.ts +229 -0
- package/Server/Utils/Topology/TopologyQueries.ts +1350 -0
- package/Server/Utils/Topology/TopologyRequest.ts +463 -0
- package/Server/Utils/Topology/TopologyResponseCache.ts +183 -0
- package/Server/Utils/Topology/TopologySql.ts +1024 -0
- package/Server/Utils/VM/VMAPI.ts +1 -0
- package/Server/Utils/VM/VMRunner.ts +10 -0
- package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
- package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
- package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
- package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
- package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
- package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
- package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
- package/Tests/App/Dashboard/AcknowledgeAlertsOnDeclare.test.ts +369 -0
- package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +1 -1
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +510 -123
- package/Tests/App/Dashboard/AlertsTableAffectedResources.test.tsx +490 -0
- package/Tests/App/Dashboard/ChangeAlertStateDeclareIncident.test.tsx +886 -0
- package/Tests/App/Dashboard/CreateReviewStepRoleSummary.test.tsx +1250 -0
- package/Tests/App/Dashboard/CreateReviewStepSelectionSummary.test.tsx +738 -0
- package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
- package/Tests/App/Dashboard/DeclareIncidentFromAlert.test.ts +417 -0
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +1948 -229
- package/Tests/App/Dashboard/EntityDetailPanelLifecycle.test.tsx +493 -0
- package/Tests/App/Dashboard/EntityDetailPanelNavigation.test.tsx +439 -0
- package/Tests/App/Dashboard/EventNotes.test.tsx +776 -0
- package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
- package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
- package/Tests/App/Dashboard/EventOverviewPages.test.tsx +534 -6
- package/Tests/App/Dashboard/EventStatusPanel.test.tsx +798 -2
- package/Tests/App/Dashboard/FetchStateAndSeverityElements.test.tsx +669 -0
- package/Tests/App/Dashboard/FetchUsers.test.tsx +230 -0
- package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
- package/Tests/App/Dashboard/IncidentCreateAcknowledgeAlerts.test.tsx +1611 -0
- package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
- package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
- package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
- package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
- package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
- package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
- package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
- package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
- package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
- package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
- package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +1365 -57
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +964 -23
- package/Tests/App/Dashboard/InventoryRelationships.test.tsx +885 -0
- package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
- package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +201 -15
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +508 -36
- package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
- package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
- package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
- package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
- package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
- package/Tests/App/Dashboard/TopologyDataLifecycle.test.tsx +583 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +982 -218
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +818 -114
- package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
- package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
- package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
- package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
- package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
- package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
- package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
- package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
- package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
- package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
- package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
- package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
- package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
- package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
- package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
- package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
- package/Tests/Server/Infrastructure/Postgres/RenameInventoryItemMigration.test.ts +90 -21
- package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
- package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
- package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
- package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
- package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
- package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
- package/Tests/Server/Services/DomainService.test.ts +525 -0
- package/Tests/Server/Services/IncidentAlertAcknowledgeOnDeclare.test.ts +2630 -0
- package/Tests/Server/Services/IncidentAlertPostgres.test.ts +1625 -1
- package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
- package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
- package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
- package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
- package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
- package/Tests/Server/Services/IncidentDeclareAcknowledgeAlerts.test.ts +2189 -0
- package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
- package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
- package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
- package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
- package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
- package/Tests/Server/Services/InventoryItemServiceOverviewCounts.test.ts +345 -0
- package/Tests/Server/Services/InventoryOverviewPostgres.test.ts +254 -0
- package/Tests/Server/Services/IoTDeviceCredentialService.test.ts +819 -0
- package/Tests/Server/Services/LinkedAffectedResourcesCreatedFeed.test.ts +420 -0
- package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
- package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
- package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
- package/Tests/Server/Services/SloAffectedResourceCreatedFeed.test.ts +92 -36
- package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
- package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
- package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
- package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
- package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
- package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
- package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
- package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
- package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
- package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
- package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
- package/Tests/Server/Utils/AffectedResources/LinkedAffectedResources.test.ts +858 -0
- package/Tests/Server/Utils/Alert/AlertStateChangeAuthorization.test.ts +1172 -0
- package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
- package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
- package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
- package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
- package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
- package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
- package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
- package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
- package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
- package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
- package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
- package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
- package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
- package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
- package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
- package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigration.test.ts +386 -0
- package/Tests/Server/Utils/Topology/InventoryItemEntityKeyIndexMigrationPostgres.test.ts +430 -0
- package/Tests/Server/Utils/Topology/TopologyActivityParityPostgres.test.ts +279 -0
- package/Tests/Server/Utils/Topology/TopologyConcurrencyLimiter.test.ts +534 -0
- package/Tests/Server/Utils/Topology/TopologyEstateGenerator.ts +624 -0
- package/Tests/Server/Utils/Topology/TopologyJsonResponse.test.ts +90 -0
- package/Tests/Server/Utils/Topology/TopologyQueries.test.ts +1634 -0
- package/Tests/Server/Utils/Topology/TopologyQueriesDifferentialPostgres.test.ts +683 -0
- package/Tests/Server/Utils/Topology/TopologyQueriesPostgres.test.ts +2624 -0
- package/Tests/Server/Utils/Topology/TopologyReference.ts +1018 -0
- package/Tests/Server/Utils/Topology/TopologyRequest.test.ts +643 -0
- package/Tests/Server/Utils/Topology/TopologyResponseCache.test.ts +305 -0
- package/Tests/Server/Utils/Topology/TopologySql.test.ts +973 -0
- package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
- package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
- package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
- package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
- package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
- package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
- package/Tests/Types/SafeHtml.test.ts +102 -0
- package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
- package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
- package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
- package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
- package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
- package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
- package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
- package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
- package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
- package/Tests/Types/Topology/TopologyTypeRules.test.ts +176 -0
- package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
- package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
- package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
- package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
- package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
- package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +302 -0
- package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
- package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
- package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
- package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
- package/Types/CustomField/CustomFieldOrder.ts +55 -0
- package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
- package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
- package/Types/CustomField/CustomFieldType.ts +14 -0
- package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
- package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
- package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
- package/Types/Incident/IncidentAlertLink.ts +19 -0
- package/Types/SafeHtml.ts +93 -0
- package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
- package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
- package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
- package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
- package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
- package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
- package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
- package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
- package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
- package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
- package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
- package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
- package/Types/Telemetry/InventoryLiveness.ts +26 -0
- package/Types/Topology/TopologyApi.ts +428 -0
- package/Types/Topology/TopologyTypeRules.ts +191 -0
- package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
- package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
- package/UI/Components/Forms/ModelForm.tsx +70 -8
- package/UI/Components/Forms/Validation.ts +1 -1
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
- package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
- package/UI/Components/ModelTable/BaseModelTable.tsx +9 -8
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
- package/UI/Components/ModelTable/ModelTable.tsx +6 -7
- package/UI/Utils/SensitiveUrlToken.ts +10 -5
- package/Utils/API.ts +247 -2
- package/Utils/Incident/IncidentFromAlerts.ts +78 -0
- package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
- package/Utils/Markdown/MarkdownEscape.ts +65 -0
- package/Utils/ProbeNetworkFailureUtil.ts +673 -0
- package/build/dist/Models/DatabaseModels/Incident.js +267 -1
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
- package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
- package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
- package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js +20 -11
- package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
- package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
- package/build/dist/Server/API/IncidentAPI.js +100 -1
- package/build/dist/Server/API/IncidentAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +417 -176
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
- package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js +165 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795200000000-AddInventoryItemProjectEntityKeyIndex.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
- package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
- package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
- package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
- package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
- package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
- package/build/dist/Server/Services/AlertService.js +21 -33
- package/build/dist/Server/Services/AlertService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +56 -7
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/IncidentAlertService.js +457 -3
- package/build/dist/Server/Services/IncidentAlertService.js.map +1 -1
- package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
- package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
- package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
- package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +1148 -42
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
- package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +31 -0
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/IoTDeviceCredentialService.js +12 -5
- package/build/dist/Server/Services/IoTDeviceCredentialService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceService.js +84 -57
- package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
- package/build/dist/Server/Services/SmsService.js +2 -22
- package/build/dist/Server/Services/SmsService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +47 -9
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
- package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
- package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +55 -51
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +42 -25
- package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +110 -6
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
- package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
- package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js +405 -0
- package/build/dist/Server/Utils/AffectedResources/LinkedAffectedResources.js.map +1 -0
- package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js +112 -0
- package/build/dist/Server/Utils/Alert/AlertStateChangeAuthorization.js.map +1 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
- package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js +81 -0
- package/build/dist/Server/Utils/Inventory/InventoryOverviewAggregation.js.map +1 -0
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
- package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +30 -0
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +48 -6
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
- package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
- package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
- package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
- package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
- package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
- package/build/dist/Server/Utils/StatusPageResource.js +39 -7
- package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
- package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js +178 -0
- package/build/dist/Server/Utils/Topology/TopologyConcurrencyLimiter.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyQueries.js +884 -0
- package/build/dist/Server/Utils/Topology/TopologyQueries.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyRequest.js +275 -0
- package/build/dist/Server/Utils/Topology/TopologyRequest.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologyResponseCache.js +146 -0
- package/build/dist/Server/Utils/Topology/TopologyResponseCache.js.map +1 -0
- package/build/dist/Server/Utils/Topology/TopologySql.js +688 -0
- package/build/dist/Server/Utils/Topology/TopologySql.js.map +1 -0
- package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
- package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
- package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
- package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
- package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
- package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
- package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
- package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js +17 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -1
- package/build/dist/Types/SafeHtml.js +84 -0
- package/build/dist/Types/SafeHtml.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
- package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
- package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
- package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
- package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
- package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
- package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
- package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
- package/build/dist/Types/Telemetry/InventoryLiveness.js +23 -0
- package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -1
- package/build/dist/Types/Topology/TopologyApi.js +55 -0
- package/build/dist/Types/Topology/TopologyApi.js.map +1 -0
- package/build/dist/Types/Topology/TopologyTypeRules.js +165 -0
- package/build/dist/Types/Topology/TopologyTypeRules.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +1 -1
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
- package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
- package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
- package/build/dist/Utils/API.js +177 -1
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentFromAlerts.js +38 -0
- package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
- package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
- package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
- package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
- package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import APIException from "../../Types/Exception/ApiException";
|
|
1
2
|
import BadDataException from "../../Types/Exception/BadDataException";
|
|
2
3
|
import EgressGuardException, {
|
|
3
4
|
EgressFailureReason,
|
|
@@ -323,3 +324,577 @@ describe("API.getRequestFailedDetails - existing classification", () => {
|
|
|
323
324
|
expect(details.rawErrorMessage).toBe("something odd");
|
|
324
325
|
});
|
|
325
326
|
});
|
|
327
|
+
|
|
328
|
+
/*
|
|
329
|
+
* A probe with no usable IPv6 fails every IPv6 URL before a packet leaves
|
|
330
|
+
* it. The reported case was a Ping monitor for 2001:518:2800:9::2, which
|
|
331
|
+
* answers every echo from a host that has IPv6; a Website or API monitor for
|
|
332
|
+
* the same address fails the same way, with "connect EADDRNOTAVAIL".
|
|
333
|
+
*
|
|
334
|
+
* The error shapes below are the ones Node 26 and axios 1.20 actually
|
|
335
|
+
* produce, captured in a container with IPv6 disabled on loopback (the
|
|
336
|
+
* customer's probe: EADDRNOTAVAIL) and in one with no IPv6 route
|
|
337
|
+
* (ENETUNREACH).
|
|
338
|
+
*/
|
|
339
|
+
|
|
340
|
+
const CUSTOMER_IPV6_ADDRESS: string = "2001:518:2800:9::2";
|
|
341
|
+
const CUSTOMER_IPV6_URL: string = `https://[${CUSTOMER_IPV6_ADDRESS}]/`;
|
|
342
|
+
const IPV4_ADDRESS: string = "93.184.215.14";
|
|
343
|
+
|
|
344
|
+
// EAFNOSUPPORT: only a probe with IPv6 switched off gets it.
|
|
345
|
+
const IPV6_NOT_SENT_DETAILS: string =
|
|
346
|
+
"The probe cannot send IPv6 traffic, so the request was never sent and the server was never contacted. The failure is on the probe, not on the server.";
|
|
347
|
+
/*
|
|
348
|
+
* EADDRNOTAVAIL: from a TCP connect it can also be the probe running out of
|
|
349
|
+
* local ports, so it is not stated as missing IPv6.
|
|
350
|
+
*/
|
|
351
|
+
const IPV6_NO_SOURCE_ADDRESS_DETAILS: string =
|
|
352
|
+
"The probe could not open the IPv6 connection from its own side, so the request was never sent and the server was never contacted. The failure is on the probe, not on the server.";
|
|
353
|
+
const IPV6_NO_ROUTE_DETAILS: string =
|
|
354
|
+
"There was no IPv6 route to the server. Most likely the probe has no IPv6 route rather than the server being down.";
|
|
355
|
+
const NOT_SENT_DETAILS: string =
|
|
356
|
+
"The probe could not open the connection from its own side, so the request was never sent and the server was never contacted. The failure is on the probe, not on the server.";
|
|
357
|
+
// The description ENETUNREACH has always had, kept for anything but IPv6.
|
|
358
|
+
const NETWORK_UNREACHABLE_DETAILS: string =
|
|
359
|
+
"Network unreachable. There is no route to the network where the server resides. This is typically a routing or connectivity issue.";
|
|
360
|
+
|
|
361
|
+
const ERRNO_BY_CODE: Record<string, number> = {
|
|
362
|
+
EADDRNOTAVAIL: -99,
|
|
363
|
+
EAFNOSUPPORT: -97,
|
|
364
|
+
ENETUNREACH: -101,
|
|
365
|
+
EHOSTUNREACH: -113,
|
|
366
|
+
ECONNREFUSED: -111,
|
|
367
|
+
ETIMEDOUT: -110,
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
// The socket error net.connect rejects with, field for field.
|
|
371
|
+
function connectError(data: {
|
|
372
|
+
code: string;
|
|
373
|
+
address: string;
|
|
374
|
+
port: number;
|
|
375
|
+
}): Error {
|
|
376
|
+
const local: string = data.address.includes(":") ? ":::0" : "0.0.0.0:0";
|
|
377
|
+
|
|
378
|
+
return Object.assign(
|
|
379
|
+
new Error(
|
|
380
|
+
`connect ${data.code} ${data.address}:${data.port} - Local (${local})`,
|
|
381
|
+
),
|
|
382
|
+
{
|
|
383
|
+
errno: ERRNO_BY_CODE[data.code],
|
|
384
|
+
code: data.code,
|
|
385
|
+
syscall: "connect",
|
|
386
|
+
address: data.address,
|
|
387
|
+
port: data.port,
|
|
388
|
+
},
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/*
|
|
393
|
+
* What Node rejects with when it tried several addresses of a dual-stack
|
|
394
|
+
* name: an empty message, the first attempt's code, one error per attempt.
|
|
395
|
+
*/
|
|
396
|
+
function happyEyeballsError(attempts: Array<Error>): Error {
|
|
397
|
+
return Object.assign(new Error(""), {
|
|
398
|
+
name: "AggregateError",
|
|
399
|
+
code: (attempts[0] as Error & { code: string }).code,
|
|
400
|
+
errors: attempts,
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/*
|
|
405
|
+
* What axios's HTTP adapter rejects with around a socket error. This is the
|
|
406
|
+
* adapter's own call (AxiosError.from(err, null, config, req)), so the
|
|
407
|
+
* wrapper is exactly what the Website monitor catches.
|
|
408
|
+
*/
|
|
409
|
+
function axiosConnectError(url: string, cause: Error): AxiosError {
|
|
410
|
+
return AxiosError.from(
|
|
411
|
+
cause,
|
|
412
|
+
undefined,
|
|
413
|
+
{ url: url, headers: new AxiosHeaders() } as InternalAxiosRequestConfig,
|
|
414
|
+
{},
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/*
|
|
419
|
+
* What the API monitor catches for the same failure: API.fetch hands the
|
|
420
|
+
* AxiosError to getErrorResponse, which wraps it in an APIException.
|
|
421
|
+
*/
|
|
422
|
+
function apiMonitorError(axiosError: AxiosError): APIException {
|
|
423
|
+
try {
|
|
424
|
+
API["getErrorResponse"](axiosError);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
return error as APIException;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
throw new Error("getErrorResponse returned instead of throwing");
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// What fetch() rejects with: the socket error is only on `cause`.
|
|
433
|
+
function fetchError(cause: Error): Error {
|
|
434
|
+
return Object.assign(new TypeError("fetch failed"), { cause: cause });
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function customerAxiosError(): AxiosError {
|
|
438
|
+
return axiosConnectError(
|
|
439
|
+
CUSTOMER_IPV6_URL,
|
|
440
|
+
connectError({
|
|
441
|
+
code: "EADDRNOTAVAIL",
|
|
442
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
443
|
+
port: 443,
|
|
444
|
+
}),
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
describe("API.getRequestFailedDetails - failures on the probe itself", () => {
|
|
449
|
+
/*
|
|
450
|
+
* REGRESSION: EADDRNOTAVAIL matched no rule and fell through to the
|
|
451
|
+
* "request was made but no response" branch, which told the customer
|
|
452
|
+
* "The request was sent but no response was returned ... the server is
|
|
453
|
+
* down, unreachable, or the request timed out". Nothing was sent.
|
|
454
|
+
*/
|
|
455
|
+
test("the customer's IPv6 URL on a probe with no IPv6 is a probe failure, not a silent server", () => {
|
|
456
|
+
const error: AxiosError = customerAxiosError();
|
|
457
|
+
|
|
458
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(error);
|
|
459
|
+
|
|
460
|
+
expect(details).toEqual({
|
|
461
|
+
failedPhase: RequestFailedPhase.TCPConnection,
|
|
462
|
+
errorCode: "EADDRNOTAVAIL",
|
|
463
|
+
errorDescription: IPV6_NO_SOURCE_ADDRESS_DETAILS,
|
|
464
|
+
rawErrorMessage: `connect EADDRNOTAVAIL ${CUSTOMER_IPV6_ADDRESS}:443 - Local (:::0)`,
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// The old fall-through (phase Network Error), asserted as gone.
|
|
468
|
+
expect(details.failedPhase).not.toBe(RequestFailedPhase.NetworkError);
|
|
469
|
+
expect(details.errorDescription).not.toContain("No response received");
|
|
470
|
+
expect(details.errorDescription).not.toContain("was sent");
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
test("the API monitor's APIException around the same error is classified the same way", () => {
|
|
474
|
+
const error: APIException = apiMonitorError(customerAxiosError());
|
|
475
|
+
|
|
476
|
+
// The wrapper, as the monitor sees it.
|
|
477
|
+
expect(error).toBeInstanceOf(APIException);
|
|
478
|
+
expect(error.message).toBe(
|
|
479
|
+
`Request failed to ${CUSTOMER_IPV6_URL}. connect EADDRNOTAVAIL ${CUSTOMER_IPV6_ADDRESS}:443 - Local (:::0)`,
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(error);
|
|
483
|
+
|
|
484
|
+
// Used to be phase Unknown, "Request failed: Request failed to ...".
|
|
485
|
+
expect(details.failedPhase).toBe(RequestFailedPhase.TCPConnection);
|
|
486
|
+
expect(details.errorCode).toBe("EADDRNOTAVAIL");
|
|
487
|
+
expect(details.errorDescription).toBe(IPV6_NO_SOURCE_ADDRESS_DETAILS);
|
|
488
|
+
expect(details.rawErrorMessage).toBe(error.message);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
test("fetch's TypeError, whose only clue is its cause, is classified too", () => {
|
|
492
|
+
const error: Error = fetchError(
|
|
493
|
+
connectError({
|
|
494
|
+
code: "EADDRNOTAVAIL",
|
|
495
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
496
|
+
port: 443,
|
|
497
|
+
}),
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(error);
|
|
501
|
+
|
|
502
|
+
// Used to be phase Unknown, "Request failed: fetch failed".
|
|
503
|
+
expect(details.failedPhase).toBe(RequestFailedPhase.TCPConnection);
|
|
504
|
+
// TypeError has no code of its own; the one reported is the socket's.
|
|
505
|
+
expect(details.errorCode).toBe("EADDRNOTAVAIL");
|
|
506
|
+
expect(details.errorDescription).toBe(IPV6_NO_SOURCE_ADDRESS_DETAILS);
|
|
507
|
+
expect(details.rawErrorMessage).toBe("fetch failed");
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
test("EAFNOSUPPORT (IPv6 switched off in the kernel) is a probe failure", () => {
|
|
511
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(
|
|
512
|
+
axiosConnectError(
|
|
513
|
+
CUSTOMER_IPV6_URL,
|
|
514
|
+
connectError({
|
|
515
|
+
code: "EAFNOSUPPORT",
|
|
516
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
517
|
+
port: 443,
|
|
518
|
+
}),
|
|
519
|
+
),
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
expect(details.failedPhase).toBe(RequestFailedPhase.TCPConnection);
|
|
523
|
+
expect(details.errorCode).toBe("EAFNOSUPPORT");
|
|
524
|
+
expect(details.errorDescription).toBe(IPV6_NOT_SENT_DETAILS);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
test("ENETUNREACH towards an IPv6 URL is hedged towards the probe having no IPv6 route", () => {
|
|
528
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(
|
|
529
|
+
axiosConnectError(
|
|
530
|
+
CUSTOMER_IPV6_URL,
|
|
531
|
+
connectError({
|
|
532
|
+
code: "ENETUNREACH",
|
|
533
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
534
|
+
port: 443,
|
|
535
|
+
}),
|
|
536
|
+
),
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
expect(details.failedPhase).toBe(RequestFailedPhase.TCPConnection);
|
|
540
|
+
expect(details.errorCode).toBe("ENETUNREACH");
|
|
541
|
+
expect(details.errorDescription).toBe(IPV6_NO_ROUTE_DETAILS);
|
|
542
|
+
// It used to put the missing route at the server's end.
|
|
543
|
+
expect(details.errorDescription).not.toBe(NETWORK_UNREACHABLE_DETAILS);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
test("ENETUNREACH towards an IPv4 URL keeps exactly the description it had", () => {
|
|
547
|
+
const error: AxiosError = axiosConnectError(
|
|
548
|
+
`http://${IPV4_ADDRESS}/`,
|
|
549
|
+
connectError({ code: "ENETUNREACH", address: IPV4_ADDRESS, port: 80 }),
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
expect(API.getRequestFailedDetails(error)).toEqual({
|
|
553
|
+
failedPhase: RequestFailedPhase.TCPConnection,
|
|
554
|
+
errorCode: "ENETUNREACH",
|
|
555
|
+
errorDescription: NETWORK_UNREACHABLE_DETAILS,
|
|
556
|
+
rawErrorMessage: `connect ENETUNREACH ${IPV4_ADDRESS}:80 - Local (0.0.0.0:0)`,
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
test("ENETUNREACH seen only on fetch's cause gets that same family-neutral description", () => {
|
|
561
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(
|
|
562
|
+
fetchError(
|
|
563
|
+
connectError({ code: "ENETUNREACH", address: IPV4_ADDRESS, port: 80 }),
|
|
564
|
+
),
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
expect(details.failedPhase).toBe(RequestFailedPhase.TCPConnection);
|
|
568
|
+
expect(details.errorCode).toBe("ENETUNREACH");
|
|
569
|
+
expect(details.errorDescription).toBe(NETWORK_UNREACHABLE_DETAILS);
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
test("EADDRNOTAVAIL towards IPv4 is still the probe's, and says nothing about IPv6", () => {
|
|
573
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(
|
|
574
|
+
axiosConnectError(
|
|
575
|
+
`http://${IPV4_ADDRESS}/`,
|
|
576
|
+
connectError({
|
|
577
|
+
code: "EADDRNOTAVAIL",
|
|
578
|
+
address: IPV4_ADDRESS,
|
|
579
|
+
port: 80,
|
|
580
|
+
}),
|
|
581
|
+
),
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
expect(details.failedPhase).toBe(RequestFailedPhase.TCPConnection);
|
|
585
|
+
expect(details.errorCode).toBe("EADDRNOTAVAIL");
|
|
586
|
+
expect(details.errorDescription).toBe(NOT_SENT_DETAILS);
|
|
587
|
+
expect(details.errorDescription).not.toContain("IPv6");
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
test("a DNS name that only has an IPv6 address is worded as IPv6, from the address the probe dialled", () => {
|
|
591
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(
|
|
592
|
+
axiosConnectError(
|
|
593
|
+
"https://ipv6only.example.com/",
|
|
594
|
+
connectError({
|
|
595
|
+
code: "ENETUNREACH",
|
|
596
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
597
|
+
port: 443,
|
|
598
|
+
}),
|
|
599
|
+
),
|
|
600
|
+
);
|
|
601
|
+
|
|
602
|
+
expect(details.errorDescription).toBe(IPV6_NO_ROUTE_DETAILS);
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
test("a dual-stack name whose IPv4 attempt also had no route is not called an IPv6 problem", () => {
|
|
606
|
+
// Captured on a probe with no network at all: both families fail.
|
|
607
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(
|
|
608
|
+
axiosConnectError(
|
|
609
|
+
"https://dualstack.example.com/",
|
|
610
|
+
happyEyeballsError([
|
|
611
|
+
connectError({
|
|
612
|
+
code: "EADDRNOTAVAIL",
|
|
613
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
614
|
+
port: 443,
|
|
615
|
+
}),
|
|
616
|
+
connectError({
|
|
617
|
+
code: "ENETUNREACH",
|
|
618
|
+
address: IPV4_ADDRESS,
|
|
619
|
+
port: 443,
|
|
620
|
+
}),
|
|
621
|
+
]),
|
|
622
|
+
),
|
|
623
|
+
);
|
|
624
|
+
|
|
625
|
+
expect(details.failedPhase).toBe(RequestFailedPhase.TCPConnection);
|
|
626
|
+
// The attempt the description is about, not the first one Node copied.
|
|
627
|
+
expect(details.errorCode).toBe("ENETUNREACH");
|
|
628
|
+
expect(details.errorDescription).toBe(NETWORK_UNREACHABLE_DETAILS);
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
test("a dual-stack name whose IPv4 attempt was refused is the host's answer, not a probe failure", () => {
|
|
632
|
+
const error: AxiosError = axiosConnectError(
|
|
633
|
+
"https://dualstack.example.com/",
|
|
634
|
+
happyEyeballsError([
|
|
635
|
+
connectError({
|
|
636
|
+
code: "EADDRNOTAVAIL",
|
|
637
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
638
|
+
port: 443,
|
|
639
|
+
}),
|
|
640
|
+
connectError({
|
|
641
|
+
code: "ECONNREFUSED",
|
|
642
|
+
address: IPV4_ADDRESS,
|
|
643
|
+
port: 443,
|
|
644
|
+
}),
|
|
645
|
+
]),
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(error);
|
|
649
|
+
|
|
650
|
+
// What it was before: the refused IPv4 attempt decides.
|
|
651
|
+
expect(details.failedPhase).toBe(RequestFailedPhase.TCPConnection);
|
|
652
|
+
expect(details.errorDescription.startsWith("Connection refused.")).toBe(
|
|
653
|
+
true,
|
|
654
|
+
);
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
test("with no address on the error, an IPv6 literal URL is what makes it IPv6", () => {
|
|
658
|
+
const error: AxiosError = new AxiosError(
|
|
659
|
+
"connect EADDRNOTAVAIL",
|
|
660
|
+
"EADDRNOTAVAIL",
|
|
661
|
+
{
|
|
662
|
+
url: CUSTOMER_IPV6_URL,
|
|
663
|
+
headers: new AxiosHeaders(),
|
|
664
|
+
} as InternalAxiosRequestConfig,
|
|
665
|
+
{},
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
expect(API.getRequestFailedDetails(error).errorDescription).toBe(
|
|
669
|
+
IPV6_NO_SOURCE_ADDRESS_DETAILS,
|
|
670
|
+
);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
test("the address the probe dialled beats the URL: an IPv4 proxy it could not reach is not an IPv6 problem", () => {
|
|
674
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(
|
|
675
|
+
axiosConnectError(
|
|
676
|
+
CUSTOMER_IPV6_URL,
|
|
677
|
+
connectError({
|
|
678
|
+
code: "EADDRNOTAVAIL",
|
|
679
|
+
address: "192.0.2.10",
|
|
680
|
+
port: 3128,
|
|
681
|
+
}),
|
|
682
|
+
),
|
|
683
|
+
);
|
|
684
|
+
|
|
685
|
+
expect(details.errorDescription).toBe(NOT_SENT_DETAILS);
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
/*
|
|
689
|
+
* Refused, reset, timed out and "host unreachable" say something real
|
|
690
|
+
* about the destination or the path to it, IPv6 or not. They must keep
|
|
691
|
+
* their old classification.
|
|
692
|
+
*/
|
|
693
|
+
test.each([
|
|
694
|
+
["ECONNREFUSED", RequestFailedPhase.TCPConnection, "Connection refused."],
|
|
695
|
+
["ETIMEDOUT", RequestFailedPhase.RequestTimeout, "Request timed out."],
|
|
696
|
+
["EHOSTUNREACH", RequestFailedPhase.TCPConnection, "Host unreachable."],
|
|
697
|
+
])(
|
|
698
|
+
"%s from an IPv6 URL is classified as before",
|
|
699
|
+
(
|
|
700
|
+
code: string,
|
|
701
|
+
expectedPhase: RequestFailedPhase,
|
|
702
|
+
expectedStart: string,
|
|
703
|
+
) => {
|
|
704
|
+
const details: RequestFailedDetails = API.getRequestFailedDetails(
|
|
705
|
+
axiosConnectError(
|
|
706
|
+
CUSTOMER_IPV6_URL,
|
|
707
|
+
connectError({
|
|
708
|
+
code: code,
|
|
709
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
710
|
+
port: 443,
|
|
711
|
+
}),
|
|
712
|
+
),
|
|
713
|
+
);
|
|
714
|
+
|
|
715
|
+
expect(details.failedPhase).toBe(expectedPhase);
|
|
716
|
+
expect(details.errorCode).toBe(code);
|
|
717
|
+
expect(details.errorDescription.startsWith(expectedStart)).toBe(true);
|
|
718
|
+
},
|
|
719
|
+
);
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
describe("API.getProbeNetworkFailureDescription", () => {
|
|
723
|
+
test("gives the customer's IPv6 failure the shared probe-side wording, naming the host", () => {
|
|
724
|
+
expect(API.getProbeNetworkFailureDescription(customerAxiosError())).toBe(
|
|
725
|
+
`This probe could not open an IPv6 connection from its own side (connect EADDRNOTAVAIL ${CUSTOMER_IPV6_ADDRESS}:443 - Local (:::0)), so ${CUSTOMER_IPV6_ADDRESS} was never contacted. This usually means the probe has no usable IPv6 address or route (less often, that it has run out of local ports); this says nothing about whether ${CUSTOMER_IPV6_ADDRESS} is up. Monitor IPv6 destinations from a probe that has IPv6 connectivity.`,
|
|
726
|
+
);
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
test("reads through the API monitor's APIException", () => {
|
|
730
|
+
expect(
|
|
731
|
+
API.getProbeNetworkFailureDescription(
|
|
732
|
+
apiMonitorError(customerAxiosError()),
|
|
733
|
+
),
|
|
734
|
+
).toBe(API.getProbeNetworkFailureDescription(customerAxiosError()));
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
test("names the DNS name the monitor uses, not the address it resolved to", () => {
|
|
738
|
+
const description: string | null = API.getProbeNetworkFailureDescription(
|
|
739
|
+
axiosConnectError(
|
|
740
|
+
"https://ipv6only.example.com/health",
|
|
741
|
+
connectError({
|
|
742
|
+
code: "EADDRNOTAVAIL",
|
|
743
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
744
|
+
port: 443,
|
|
745
|
+
}),
|
|
746
|
+
),
|
|
747
|
+
);
|
|
748
|
+
|
|
749
|
+
expect(description).toContain(
|
|
750
|
+
"so ipv6only.example.com was never contacted",
|
|
751
|
+
);
|
|
752
|
+
expect(description).toContain(
|
|
753
|
+
"This probe could not open an IPv6 connection from its own side",
|
|
754
|
+
);
|
|
755
|
+
});
|
|
756
|
+
|
|
757
|
+
test("hedges ENETUNREACH towards IPv6", () => {
|
|
758
|
+
expect(
|
|
759
|
+
API.getProbeNetworkFailureDescription(
|
|
760
|
+
axiosConnectError(
|
|
761
|
+
CUSTOMER_IPV6_URL,
|
|
762
|
+
connectError({
|
|
763
|
+
code: "ENETUNREACH",
|
|
764
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
765
|
+
port: 443,
|
|
766
|
+
}),
|
|
767
|
+
),
|
|
768
|
+
),
|
|
769
|
+
).toBe(
|
|
770
|
+
`This probe could not reach ${CUSTOMER_IPV6_ADDRESS} over IPv6 (connect ENETUNREACH ${CUSTOMER_IPV6_ADDRESS}:443 - Local (:::0)). Most likely this probe has no IPv6 route rather than ${CUSTOMER_IPV6_ADDRESS} being down. Monitor IPv6 destinations from a probe that has IPv6 connectivity.`,
|
|
771
|
+
);
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
test("calls the target 'the server' when the error has no request URL", () => {
|
|
775
|
+
expect(
|
|
776
|
+
API.getProbeNetworkFailureDescription(
|
|
777
|
+
fetchError(
|
|
778
|
+
connectError({
|
|
779
|
+
code: "EADDRNOTAVAIL",
|
|
780
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
781
|
+
port: 443,
|
|
782
|
+
}),
|
|
783
|
+
),
|
|
784
|
+
),
|
|
785
|
+
).toBe(
|
|
786
|
+
`This probe could not open an IPv6 connection from its own side (connect EADDRNOTAVAIL ${CUSTOMER_IPV6_ADDRESS}:443 - Local (:::0)), so the server was never contacted. This usually means the probe has no usable IPv6 address or route (less often, that it has run out of local ports); this says nothing about whether the server is up. Monitor IPv6 destinations from a probe that has IPv6 connectivity.`,
|
|
787
|
+
);
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
test("words EADDRNOTAVAIL towards IPv4 without any IPv6 claim", () => {
|
|
791
|
+
expect(
|
|
792
|
+
API.getProbeNetworkFailureDescription(
|
|
793
|
+
axiosConnectError(
|
|
794
|
+
`http://${IPV4_ADDRESS}/`,
|
|
795
|
+
connectError({
|
|
796
|
+
code: "EADDRNOTAVAIL",
|
|
797
|
+
address: IPV4_ADDRESS,
|
|
798
|
+
port: 80,
|
|
799
|
+
}),
|
|
800
|
+
),
|
|
801
|
+
),
|
|
802
|
+
).toBe(
|
|
803
|
+
`This probe could not send traffic to ${IPV4_ADDRESS} (connect EADDRNOTAVAIL ${IPV4_ADDRESS}:80 - Local (0.0.0.0:0)), so ${IPV4_ADDRESS} was never contacted. The failure is on the probe, not on ${IPV4_ADDRESS}.`,
|
|
804
|
+
);
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
test("a dual-stack name where both attempts could not leave the probe gets no IPv6 claim", () => {
|
|
808
|
+
const description: string | null = API.getProbeNetworkFailureDescription(
|
|
809
|
+
axiosConnectError(
|
|
810
|
+
"https://dualstack.example.com/",
|
|
811
|
+
happyEyeballsError([
|
|
812
|
+
connectError({
|
|
813
|
+
code: "EADDRNOTAVAIL",
|
|
814
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
815
|
+
port: 443,
|
|
816
|
+
}),
|
|
817
|
+
connectError({
|
|
818
|
+
code: "EADDRNOTAVAIL",
|
|
819
|
+
address: IPV4_ADDRESS,
|
|
820
|
+
port: 443,
|
|
821
|
+
}),
|
|
822
|
+
]),
|
|
823
|
+
),
|
|
824
|
+
);
|
|
825
|
+
|
|
826
|
+
expect(description).toContain(
|
|
827
|
+
"This probe could not send traffic to dualstack.example.com",
|
|
828
|
+
);
|
|
829
|
+
expect(description).not.toContain("IPv6");
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
test.each([
|
|
833
|
+
[
|
|
834
|
+
"ENETUNREACH towards IPv4 (a router may have sent it)",
|
|
835
|
+
axiosConnectError(
|
|
836
|
+
`http://${IPV4_ADDRESS}/`,
|
|
837
|
+
connectError({ code: "ENETUNREACH", address: IPV4_ADDRESS, port: 80 }),
|
|
838
|
+
),
|
|
839
|
+
],
|
|
840
|
+
[
|
|
841
|
+
"both families unreachable (Node tried IPv6 first)",
|
|
842
|
+
axiosConnectError(
|
|
843
|
+
"https://dualstack.example.com/",
|
|
844
|
+
happyEyeballsError([
|
|
845
|
+
connectError({
|
|
846
|
+
code: "ENETUNREACH",
|
|
847
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
848
|
+
port: 443,
|
|
849
|
+
}),
|
|
850
|
+
connectError({
|
|
851
|
+
code: "ENETUNREACH",
|
|
852
|
+
address: IPV4_ADDRESS,
|
|
853
|
+
port: 443,
|
|
854
|
+
}),
|
|
855
|
+
]),
|
|
856
|
+
),
|
|
857
|
+
],
|
|
858
|
+
[
|
|
859
|
+
"ECONNREFUSED from an IPv6 host",
|
|
860
|
+
axiosConnectError(
|
|
861
|
+
CUSTOMER_IPV6_URL,
|
|
862
|
+
connectError({
|
|
863
|
+
code: "ECONNREFUSED",
|
|
864
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
865
|
+
port: 443,
|
|
866
|
+
}),
|
|
867
|
+
),
|
|
868
|
+
],
|
|
869
|
+
[
|
|
870
|
+
"EHOSTUNREACH from an IPv6 host",
|
|
871
|
+
axiosConnectError(
|
|
872
|
+
CUSTOMER_IPV6_URL,
|
|
873
|
+
connectError({
|
|
874
|
+
code: "EHOSTUNREACH",
|
|
875
|
+
address: CUSTOMER_IPV6_ADDRESS,
|
|
876
|
+
port: 443,
|
|
877
|
+
}),
|
|
878
|
+
),
|
|
879
|
+
],
|
|
880
|
+
[
|
|
881
|
+
"an axios timeout",
|
|
882
|
+
new AxiosError("timeout of 5000ms exceeded", "ECONNABORTED"),
|
|
883
|
+
],
|
|
884
|
+
["an HTTP 500 response", createAxiosResponseError(500)],
|
|
885
|
+
[
|
|
886
|
+
"an egress guard refusal",
|
|
887
|
+
new EgressGuardException(
|
|
888
|
+
CUSTOMER_SANITIZED_MESSAGE,
|
|
889
|
+
EgressFailureReason.Unreachable,
|
|
890
|
+
),
|
|
891
|
+
],
|
|
892
|
+
["a plain error", new Error("something odd")],
|
|
893
|
+
["a thrown string", "EADDRNOTAVAIL"],
|
|
894
|
+
])(
|
|
895
|
+
"is null for %s, so the monitor keeps the message it had",
|
|
896
|
+
(_name: string, error: unknown) => {
|
|
897
|
+
expect(API.getProbeNetworkFailureDescription(error)).toBeNull();
|
|
898
|
+
},
|
|
899
|
+
);
|
|
900
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The order a record's custom fields are shown in, wherever they are shown:
|
|
3
|
+
* the Custom Fields card, the Details step of declaring an incident, and the
|
|
4
|
+
* incident custom fields that go out in status page subscriber messages.
|
|
5
|
+
*
|
|
6
|
+
* Pure, with no database or React imports, so the dashboard and the server
|
|
7
|
+
* put fields in the same order.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export type SortCustomFieldDefinitionsFunction = <
|
|
11
|
+
T extends { sortOrder?: number | null | undefined },
|
|
12
|
+
>(
|
|
13
|
+
definitions: Array<T>,
|
|
14
|
+
) => Array<T>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Fields with an order first, lowest first; fields without one after them.
|
|
18
|
+
* Stable, so fields with the same order (or none) keep the order they came
|
|
19
|
+
* in. Returns a new list.
|
|
20
|
+
*/
|
|
21
|
+
export const sortCustomFieldDefinitions: SortCustomFieldDefinitionsFunction = <
|
|
22
|
+
T extends { sortOrder?: number | null | undefined },
|
|
23
|
+
>(
|
|
24
|
+
definitions: Array<T>,
|
|
25
|
+
): Array<T> => {
|
|
26
|
+
const orderOf: (definition: T) => number = (definition: T): number => {
|
|
27
|
+
return typeof definition.sortOrder === "number" &&
|
|
28
|
+
Number.isFinite(definition.sortOrder)
|
|
29
|
+
? definition.sortOrder
|
|
30
|
+
: Number.POSITIVE_INFINITY;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return definitions
|
|
34
|
+
.map((definition: T, index: number) => {
|
|
35
|
+
return { definition, index };
|
|
36
|
+
})
|
|
37
|
+
.sort(
|
|
38
|
+
(
|
|
39
|
+
a: { definition: T; index: number },
|
|
40
|
+
b: { definition: T; index: number },
|
|
41
|
+
) => {
|
|
42
|
+
const difference: number =
|
|
43
|
+
orderOf(a.definition) - orderOf(b.definition);
|
|
44
|
+
|
|
45
|
+
if (difference !== 0 && !Number.isNaN(difference)) {
|
|
46
|
+
return difference;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return a.index - b.index;
|
|
50
|
+
},
|
|
51
|
+
)
|
|
52
|
+
.map((entry: { definition: T; index: number }) => {
|
|
53
|
+
return entry.definition;
|
|
54
|
+
});
|
|
55
|
+
};
|