@oneuptime/common 12.0.12 → 12.0.14
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/DatabaseBaseModel/DatabaseBaseModel.ts +32 -5
- package/Models/DatabaseModels/NetworkDevice.ts +64 -0
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +14 -0
- package/Models/DatabaseModels/StatusPage.ts +59 -0
- package/Models/DatabaseModels/StatusPageOidc.ts +2 -0
- package/Models/DatabaseModels/UserCall.ts +94 -3
- package/Models/DatabaseModels/UserEmail.ts +94 -3
- package/Models/DatabaseModels/UserIncomingCallNumber.ts +94 -3
- package/Models/DatabaseModels/UserPush.ts +37 -0
- package/Models/DatabaseModels/UserSMS.ts +94 -3
- package/Models/DatabaseModels/UserWhatsApp.ts +93 -2
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -2
- package/Server/API/AIChatAPI.ts +55 -56
- package/Server/API/BaseAPI.ts +79 -14
- package/Server/API/CommonAPI.ts +89 -0
- package/Server/API/MicrosoftTeamsAPI.ts +20 -9
- package/Server/API/SlackAPI.ts +13 -10
- package/Server/API/StatusPageAPI.ts +2197 -2128
- package/Server/API/TelemetryAPI.ts +72 -3
- package/Server/API/UserCallAPI.ts +53 -45
- package/Server/API/UserEmailAPI.ts +53 -44
- package/Server/API/UserIncomingCallNumberAPI.ts +48 -38
- package/Server/API/UserNotificationMethodAdminAPI.ts +481 -0
- package/Server/API/UserPushAPI.ts +126 -2
- package/Server/API/UserSmsAPI.ts +53 -44
- package/Server/API/UserWhatsAppAPI.ts +53 -50
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.ts +154 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.ts +17 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.ts +30 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.ts +45 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
- package/Server/Middleware/UserAuthorization.ts +11 -2
- package/Server/Middleware/VerificationCodeRateLimit.ts +586 -0
- package/Server/Services/AnalyticsDatabaseService.ts +169 -0
- package/Server/Services/ApiKeyPermissionService.ts +116 -2
- package/Server/Services/DatabaseService.ts +118 -6
- package/Server/Services/LogAggregationService.ts +39 -0
- package/Server/Services/LogService.ts +21 -0
- package/Server/Services/NetworkSiteService.ts +12 -0
- package/Server/Services/PushNotificationService.ts +127 -12
- package/Server/Services/SpanService.ts +21 -0
- package/Server/Services/TeamMemberService.ts +53 -13
- package/Server/Services/TraceAggregationService.ts +15 -0
- package/Server/Services/UserCallService.ts +55 -24
- package/Server/Services/UserEmailService.ts +83 -17
- package/Server/Services/UserIncomingCallNumberService.ts +49 -85
- package/Server/Services/UserNotificationMethodAdminService.ts +1527 -0
- package/Server/Services/UserNotificationRuleService.ts +26 -0
- package/Server/Services/UserPushService.ts +89 -0
- package/Server/Services/UserSmsService.ts +50 -17
- package/Server/Services/UserWhatsAppService.ts +48 -15
- package/Server/Services/WorkspaceNotificationRuleService.ts +172 -220
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
- package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -16
- package/Server/Types/Database/QueryHelper.ts +30 -0
- package/Server/Utils/APIKey/AccessPermission.ts +16 -40
- package/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.ts +59 -0
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +144 -0
- package/Server/Utils/ChannelVerification.ts +510 -0
- package/Server/Utils/LogRedaction.ts +576 -0
- package/Server/Utils/Logger.ts +123 -46
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +13 -16
- package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +94 -23
- package/Server/Utils/Monitor/MonitorAlert.ts +24 -21
- package/Server/Utils/Monitor/MonitorIncident.ts +21 -18
- package/Server/Utils/Monitor/MonitorResource.ts +29 -9
- package/Server/Utils/Monitor/MonitorResourceContext.ts +107 -0
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +442 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +28 -7
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +3 -3
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +96 -28
- package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +56 -10
- package/Server/Utils/StartServer.ts +30 -9
- package/Server/Utils/StatusPageSearchEngineIndexing.ts +33 -0
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +441 -0
- package/Server/Utils/TotpAuth.ts +137 -9
- package/Server/Utils/UserRegistrationToken.ts +182 -0
- package/Server/Utils/VerificationCode.ts +134 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +488 -46
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +173 -94
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +1151 -0
- package/Tests/App/Dashboard/AdminUserOnCallPages.test.tsx +905 -0
- package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +338 -0
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1 -1
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +328 -0
- package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +130 -0
- package/Tests/Models/DatabaseModels/DatabaseBaseModelToJSONObjectCache.test.ts +180 -0
- package/Tests/Models/StatusPageEnableSearchEngineIndexing.test.ts +157 -0
- package/Tests/Models/UserPushCriticalAlertColumn.test.ts +172 -0
- package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +23 -1
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +785 -0
- package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +21 -8
- package/Tests/Server/API/BaseAPIGetListParallel.test.ts +519 -0
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +290 -0
- package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +7 -1
- package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +543 -0
- package/Tests/Server/API/StatusPageOverviewCache.test.ts +474 -0
- package/Tests/Server/API/StatusPageSeoSearchEngineIndexing.test.ts +189 -0
- package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +108 -18
- package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +963 -0
- package/Tests/Server/API/UserPushCriticalAlertsApi.test.ts +114 -0
- package/Tests/Server/API/UserSmsApi.test.ts +107 -14
- package/Tests/Server/API/UserTotpAuthAPI.test.ts +427 -0
- package/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts +158 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +9 -60
- package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +315 -0
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +24 -15
- package/Tests/Server/Middleware/UserAuthorization.test.ts +79 -0
- package/Tests/Server/Middleware/VerificationCodeRateLimit.test.ts +775 -0
- package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +280 -0
- package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +33 -13
- package/Tests/Server/Services/AnalyticsDatabaseSortKeyBoundary.test.ts +658 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +347 -0
- package/Tests/Server/Services/CriticalOnCallAlertDelivery.test.ts +458 -0
- package/Tests/Server/Services/CriticalPushAlertPayload.test.ts +301 -0
- package/Tests/Server/Services/DatabaseServiceAtomicIncrement.test.ts +143 -0
- package/Tests/Server/Services/DatabaseServiceUpdateDebugLogging.test.ts +282 -0
- package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1 -0
- package/Tests/Server/Services/LogAggregationScanMemory.test.ts +421 -0
- package/Tests/Server/Services/LogAggregationService.test.ts +2 -2
- package/Tests/Server/Services/NetworkSiteService.test.ts +56 -2
- package/Tests/Server/Services/NotificationChannelCodeIssuance.test.ts +401 -0
- package/Tests/Server/Services/PushNotificationDeliveryOptions.test.ts +204 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +21 -1
- package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +290 -0
- package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +267 -0
- package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +948 -0
- package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1 -0
- package/Tests/Server/Services/UserPushCriticalAlertToggle.test.ts +255 -0
- package/Tests/Server/Services/UserTotpAuthEnrolment.test.ts +218 -0
- package/Tests/Server/Services/WorkspaceNotificationRuleTestRuleChannels.test.ts +702 -0
- package/Tests/Server/TestingUtils/AuthenticatorApp.ts +248 -0
- package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +165 -0
- package/Tests/Server/Types/Database/Permissions/NotificationChannelVerificationColumns.test.ts +135 -0
- package/Tests/Server/Types/Database/Permissions/OnCallScheduleRelationSelect.test.ts +504 -0
- package/Tests/Server/Types/Database/QueryHelperFindWithSameTextAnyOf.test.ts +91 -0
- package/Tests/Server/Types/Workflow/Components/JsonToText.test.ts +384 -0
- package/Tests/Server/Types/Workflow/Components/MergeJson.test.ts +403 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +48 -36
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +213 -0
- package/Tests/Server/Utils/Browser.test.ts +162 -0
- package/Tests/Server/Utils/ChannelVerification.test.ts +689 -0
- package/Tests/Server/Utils/Express.test.ts +371 -0
- package/Tests/Server/Utils/LogRedaction.test.ts +415 -0
- package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +245 -0
- package/Tests/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.test.ts +707 -0
- package/Tests/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.test.ts +698 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingEmailBodyCriteria.test.ts +243 -0
- package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestBodyCriteria.test.ts +278 -0
- package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +374 -4
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +160 -20
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +13 -8
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +162 -18
- package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +349 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +455 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +690 -0
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +7 -2
- package/Tests/Server/Utils/Monitor/NetworkDeviceReachabilityRoundTrip.test.ts +369 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +86 -8
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +92 -18
- package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +64 -0
- package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +267 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCacheStore.test.ts +207 -0
- package/Tests/Server/Utils/StartServerBodyVerify.test.ts +335 -0
- package/Tests/Server/Utils/StatusPageSearchEngineIndexing.test.ts +60 -0
- package/Tests/Server/Utils/Telemetry/OneuptimeLabel.test.ts +439 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +435 -0
- package/Tests/Server/Utils/TotpAuth.test.ts +719 -0
- package/Tests/Server/Utils/UserRegistrationToken.test.ts +322 -0
- package/Tests/Server/Utils/VerificationCode.test.ts +296 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +607 -62
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsInstalledTeamIdSpace.test.ts +778 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +44 -10
- package/Tests/Types/API/HostnameFromAuthority.test.ts +164 -0
- package/Tests/Types/AutoRemediation/AutoRemediationSuggestionStatus.test.ts +192 -0
- package/Tests/Types/Call/CallRequest.test.ts +189 -0
- package/Tests/Types/Dashboard/DashboardSize.test.ts +226 -0
- package/Tests/Types/Database/AccessControl/ColumnAccessControlCache.test.ts +344 -0
- package/Tests/Types/Database/DatabasePropertyFindOperator.test.ts +518 -0
- package/Tests/Types/Database/TableColumnMetadataCache.test.ts +286 -0
- package/Tests/Types/Incident/IncidentSlaStatus.test.ts +191 -0
- package/Tests/Types/Metrics/MetricDashboardMetricType.test.ts +278 -0
- package/Tests/Types/Metrics/MetricPipelineRuleType.test.ts +517 -0
- package/Tests/Types/Monitor/IncomingMonitorDefaultCriteria.test.ts +470 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +6 -4
- package/Tests/Types/Monitor/MonitorStep.test.ts +100 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +360 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +262 -5
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
- package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +905 -0
- package/Tests/Types/Service/ServiceLanguage.test.ts +255 -0
- package/Tests/Types/StatusPage/SearchEngineIndexing.test.ts +86 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +254 -0
- package/Tests/Types/TextRandomGeneration.test.ts +211 -0
- package/Tests/UI/Components/Button.test.tsx +175 -1
- package/Tests/UI/Components/CardSelect.test.tsx +1021 -0
- package/Tests/UI/Components/CodeBlockLanguages.test.tsx +236 -0
- package/Tests/UI/Components/CommandPalette/CommandPalette.test.tsx +568 -0
- package/Tests/UI/Components/CommandPalette/CommandPaletteKeyboard.test.tsx +239 -0
- package/Tests/UI/Components/CommandPalette/CommandPaletteProviders.test.tsx +400 -0
- package/Tests/UI/Components/CommandPalette/PaletteFilter.test.ts +234 -0
- package/Tests/UI/Components/CommandPalette/RecentCommands.test.ts +97 -0
- package/Tests/UI/Components/CountModelSideMenuItemGuard.test.tsx +198 -0
- package/Tests/UI/Components/FeedItemSafeMode.test.tsx +1 -1
- package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +267 -0
- package/Tests/UI/Components/List.test.tsx +9 -2
- package/Tests/UI/Components/ListLoadingStates.test.tsx +173 -0
- package/Tests/UI/Components/MarkdownLazy.test.tsx +113 -0
- package/Tests/UI/Components/MarkdownMermaidRetry.test.tsx +110 -0
- package/Tests/UI/Components/MasterPage.test.tsx +36 -1
- package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +8 -0
- package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +692 -0
- package/Tests/UI/Components/MoreMenuMotion.test.tsx +118 -0
- package/Tests/UI/Components/NavBarCommandKGating.test.tsx +178 -0
- package/Tests/UI/Components/OrderedStatesList.test.tsx +19 -2
- package/Tests/UI/Components/SideOverMotion.test.tsx +109 -0
- package/Tests/UI/Components/Skeleton.test.tsx +71 -0
- package/Tests/UI/Components/TableLoadingStates.test.tsx +279 -0
- package/Tests/UI/Components/Tabs.test.tsx +24 -0
- package/Tests/UI/Components/Toast.test.tsx +130 -7
- package/Tests/UI/Components/ToastStacking.test.tsx +198 -0
- package/Tests/UI/Utils/Dropdown.test.ts +423 -0
- package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +122 -0
- package/Tests/UI/Utils/ModelListCache.test.ts +338 -0
- package/Tests/UI/Utils/ProjectListCacheInvalidation.test.ts +225 -0
- package/Tests/Utils/API.test.ts +16 -2
- package/Tests/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.test.ts +347 -0
- package/Tests/Utils/Dashboard/Components/DashboardListSharedArgs.test.ts +259 -0
- package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +466 -0
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +66 -1
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +115 -6
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +610 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +114 -45
- package/Tests/Utils/Rum/UrlScrubberSegments.test.ts +362 -0
- package/Types/API/Hostname.ts +79 -0
- package/Types/Database/AccessControl/ColumnAccessControl.ts +33 -11
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +33 -11
- package/Types/Database/DatabaseProperty.ts +38 -0
- package/Types/Database/TableColumn.ts +34 -7
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/Events/Recurring.ts +16 -1
- package/Types/Monitor/MonitorCriteriaInstance.ts +41 -20
- package/Types/Monitor/MonitorStep.ts +13 -1
- package/Types/Monitor/MonitorType.ts +345 -40
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +131 -8
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +48 -8
- package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +43 -0
- package/Types/Monitor/ServiceAlertTemplates.ts +1352 -0
- package/Types/Permission.ts +35 -0
- package/Types/PushNotification/AndroidNotificationChannel.ts +26 -0
- package/Types/PushNotification/PushNotificationMessage.ts +15 -0
- package/Types/PushNotification/PushNotificationRequest.ts +8 -16
- package/Types/Service/ServiceLanguage.ts +144 -0
- package/Types/StatusPage/SearchEngineIndexing.ts +61 -0
- package/Types/Telemetry/ResourceEntityFacet.ts +211 -0
- package/Types/Text.ts +111 -19
- package/UI/Components/Button/Button.tsx +27 -14
- package/UI/Components/CardSelect/CardSelect.tsx +714 -105
- package/UI/Components/CodeBlock/CodeBlock.tsx +54 -7
- package/UI/Components/CodeBlock/LanguageRegistry.ts +103 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +790 -0
- package/UI/Components/CommandPalette/PaletteFilter.ts +196 -0
- package/UI/Components/CommandPalette/PaletteRow.tsx +173 -0
- package/UI/Components/CommandPalette/RecentCommands.ts +57 -0
- package/UI/Components/CommandPalette/Types.ts +49 -0
- package/UI/Components/CommandPalette/UseProviderSearch.ts +129 -0
- package/UI/Components/Dropdown/Dropdown.tsx +6 -1
- package/UI/Components/EmptyState/EmptyState.tsx +8 -1
- package/UI/Components/Feed/FeedItem.tsx +1 -1
- package/UI/Components/Footer/Footer.tsx +32 -6
- package/UI/Components/Forms/Fields/FormField.tsx +3 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/List/List.tsx +37 -5
- package/UI/Components/List/ListSkeleton.tsx +54 -0
- package/UI/Components/Loader/PageLoader.tsx +29 -8
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +26 -4
- package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +23 -2
- package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +71 -26
- package/UI/Components/MasterPage/MasterPage.tsx +24 -11
- package/UI/Components/Modal/Modal.tsx +2 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
- package/UI/Components/ModelTable/useCustomFieldColumns.ts +11 -5
- package/UI/Components/MoreMenu/MoreMenu.tsx +39 -1
- package/UI/Components/Navbar/NavBar.tsx +14 -1
- package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +50 -5
- package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +40 -1
- package/UI/Components/SideOver/SideOver.tsx +37 -2
- package/UI/Components/Skeleton/Skeleton.tsx +53 -0
- package/UI/Components/Table/Table.tsx +74 -44
- package/UI/Components/Table/TableSkeletonRows.tsx +141 -0
- package/UI/Components/Tabs/Tab.tsx +1 -1
- package/UI/Components/Toast/Toast.tsx +118 -53
- package/UI/Components/Toast/ToastInit.tsx +82 -32
- package/UI/Styles/Theme.css +40 -0
- package/UI/Utils/ModelAPI/ModelAPI.ts +20 -10
- package/UI/Utils/ModelListCache.ts +188 -0
- package/UI/Utils/Project.ts +29 -0
- package/Utils/API.ts +6 -1
- package/Utils/Monitor/MonitorMetricType.ts +16 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +60 -8
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +262 -0
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +41 -24
- package/Utils/Telemetry/CrossSignalScope.ts +75 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +20 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +66 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +14 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +60 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js +2 -0
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserCall.js +101 -3
- package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserEmail.js +101 -3
- package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +101 -3
- package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserPush.js +38 -0
- package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSMS.js +101 -3
- package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js +100 -2
- package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +48 -35
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +69 -13
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +59 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +20 -6
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +13 -10
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +745 -673
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +34 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/API/UserCallAPI.js +42 -38
- package/build/dist/Server/API/UserCallAPI.js.map +1 -1
- package/build/dist/Server/API/UserEmailAPI.js +42 -38
- package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js +37 -32
- package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
- package/build/dist/Server/API/UserNotificationMethodAdminAPI.js +341 -0
- package/build/dist/Server/API/UserNotificationMethodAdminAPI.js.map +1 -0
- package/build/dist/Server/API/UserPushAPI.js +95 -2
- package/build/dist/Server/API/UserPushAPI.js.map +1 -1
- package/build/dist/Server/API/UserSmsAPI.js +42 -38
- package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
- package/build/dist/Server/API/UserWhatsAppAPI.js +42 -40
- package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js +89 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js +40 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +6 -2
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/VerificationCodeRateLimit.js +393 -0
- package/build/dist/Server/Middleware/VerificationCodeRateLimit.js.map +1 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +136 -0
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +90 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +89 -6
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +7 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/LogService.js +16 -0
- package/build/dist/Server/Services/LogService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +12 -0
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/PushNotificationService.js +69 -30
- package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
- package/build/dist/Server/Services/SpanService.js +16 -0
- package/build/dist/Server/Services/SpanService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +43 -7
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +2 -0
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Services/UserCallService.js +54 -22
- package/build/dist/Server/Services/UserCallService.js.map +1 -1
- package/build/dist/Server/Services/UserEmailService.js +78 -17
- package/build/dist/Server/Services/UserEmailService.js.map +1 -1
- package/build/dist/Server/Services/UserIncomingCallNumberService.js +45 -74
- package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1117 -0
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js +20 -0
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserPushService.js +77 -0
- package/build/dist/Server/Services/UserPushService.js.map +1 -1
- package/build/dist/Server/Services/UserSmsService.js +50 -17
- package/build/dist/Server/Services/UserSmsService.js.map +1 -1
- package/build/dist/Server/Services/UserWhatsAppService.js +48 -15
- package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +137 -164
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +21 -13
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +27 -0
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/APIKey/AccessPermission.js +9 -32
- package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js +46 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +87 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/ChannelVerification.js +348 -0
- package/build/dist/Server/Utils/ChannelVerification.js.map +1 -0
- package/build/dist/Server/Utils/LogRedaction.js +449 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -0
- package/build/dist/Server/Utils/Logger.js +98 -45
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +13 -12
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +65 -13
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +20 -17
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +17 -14
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +20 -3
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +95 -0
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +313 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +27 -7
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +3 -3
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +67 -26
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +29 -10
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +10 -7
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js +24 -0
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +311 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -0
- package/build/dist/Server/Utils/TotpAuth.js +127 -8
- package/build/dist/Server/Utils/TotpAuth.js.map +1 -1
- package/build/dist/Server/Utils/UserRegistrationToken.js +170 -0
- package/build/dist/Server/Utils/UserRegistrationToken.js.map +1 -0
- package/build/dist/Server/Utils/VerificationCode.js +120 -0
- package/build/dist/Server/Utils/VerificationCode.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +366 -37
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +63 -0
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/DatabaseProperty.js +38 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/TableColumn.js +24 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Events/Recurring.js +13 -1
- package/build/dist/Types/Events/Recurring.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +42 -21
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +9 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +330 -31
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +77 -5
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +18 -6
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js +1028 -0
- package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -0
- package/build/dist/Types/Permission.js +33 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/PushNotification/AndroidNotificationChannel.js +27 -0
- package/build/dist/Types/PushNotification/AndroidNotificationChannel.js.map +1 -0
- package/build/dist/Types/Service/ServiceLanguage.js +96 -0
- package/build/dist/Types/Service/ServiceLanguage.js.map +1 -0
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js +55 -0
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js.map +1 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js +156 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -0
- package/build/dist/Types/Text.js +82 -17
- package/build/dist/Types/Text.js.map +1 -1
- package/build/dist/UI/Components/Button/Button.js +22 -14
- package/build/dist/UI/Components/Button/Button.js.map +1 -1
- package/build/dist/UI/Components/CardSelect/CardSelect.js +360 -40
- package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js +35 -3
- package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
- package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js +57 -0
- package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +439 -0
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/PaletteFilter.js +135 -0
- package/build/dist/UI/Components/CommandPalette/PaletteFilter.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/PaletteRow.js +83 -0
- package/build/dist/UI/Components/CommandPalette/PaletteRow.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/RecentCommands.js +47 -0
- package/build/dist/UI/Components/CommandPalette/RecentCommands.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/Types.js +2 -0
- package/build/dist/UI/Components/CommandPalette/Types.js.map +1 -0
- package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js +88 -0
- package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js.map +1 -0
- package/build/dist/UI/Components/Dropdown/Dropdown.js +6 -1
- package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js +1 -1
- package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
- package/build/dist/UI/Components/Footer/Footer.js +7 -4
- package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/List/List.js +19 -5
- package/build/dist/UI/Components/List/List.js.map +1 -1
- package/build/dist/UI/Components/List/ListSkeleton.js +21 -0
- package/build/dist/UI/Components/List/ListSkeleton.js.map +1 -0
- package/build/dist/UI/Components/Loader/PageLoader.js +15 -5
- package/build/dist/UI/Components/Loader/PageLoader.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +16 -3
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js +13 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +52 -25
- package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js +10 -2
- package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +2 -2
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +9 -2
- package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js +32 -1
- package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +5 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +29 -5
- package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +23 -1
- package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +23 -2
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Components/Skeleton/Skeleton.js +23 -0
- package/build/dist/UI/Components/Skeleton/Skeleton.js.map +1 -0
- package/build/dist/UI/Components/Table/Table.js +35 -24
- package/build/dist/UI/Components/Table/Table.js.map +1 -1
- package/build/dist/UI/Components/Table/TableSkeletonRows.js +52 -0
- package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -0
- package/build/dist/UI/Components/Tabs/Tab.js +1 -1
- package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
- package/build/dist/UI/Components/Toast/Toast.js +77 -23
- package/build/dist/UI/Components/Toast/Toast.js.map +1 -1
- package/build/dist/UI/Components/Toast/ToastInit.js +37 -15
- package/build/dist/UI/Components/Toast/ToastInit.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -9
- package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
- package/build/dist/UI/Utils/ModelListCache.js +126 -0
- package/build/dist/UI/Utils/ModelListCache.js.map +1 -0
- package/build/dist/UI/Utils/Project.js +24 -1
- package/build/dist/UI/Utils/Project.js.map +1 -1
- package/build/dist/Utils/API.js +6 -1
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +13 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +34 -7
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +177 -0
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +23 -27
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/CrossSignalScope.js +44 -4
- package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
- package/jest.config.json +1 -1
- package/package.json +2 -3
- package/Server/Utils/Monitor/MonitorClusterContext.ts +0 -182
- package/Tests/__mocks__/otpauth.js +0 -30
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +0 -141
- package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +0 -1
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import UserTotpAuthAPI from "../../../Server/API/UserTotpAuthAPI";
|
|
2
|
+
import UserTotpAuthService from "../../../Server/Services/UserTotpAuthService";
|
|
3
|
+
import UserService from "../../../Server/Services/UserService";
|
|
4
|
+
import TotpAuth from "../../../Server/Utils/TotpAuth";
|
|
5
|
+
import {
|
|
6
|
+
NextFunction,
|
|
7
|
+
OneUptimeRequest,
|
|
8
|
+
OneUptimeResponse,
|
|
9
|
+
} from "../../../Server/Utils/Express";
|
|
10
|
+
import Response from "../../../Server/Utils/Response";
|
|
11
|
+
import { mockRouter } from "./Helpers";
|
|
12
|
+
import Email from "../../../Types/Email";
|
|
13
|
+
import BadDataException from "../../../Types/Exception/BadDataException";
|
|
14
|
+
import Exception from "../../../Types/Exception/Exception";
|
|
15
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
16
|
+
import UserTotpAuth from "../../../Models/DatabaseModels/UserTotpAuth";
|
|
17
|
+
import User from "../../../Models/DatabaseModels/User";
|
|
18
|
+
import * as OTPAuth from "otpauth";
|
|
19
|
+
import { afterEach, beforeEach, describe, expect, test } from "@jest/globals";
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* POST /user-totp-auth/validate — the endpoint that turns a scanned QR code
|
|
23
|
+
* into a working second factor.
|
|
24
|
+
*
|
|
25
|
+
* TotpAuth itself is deliberately NOT mocked here. The bug this endpoint
|
|
26
|
+
* failed on (issue #3275) lived precisely in the seam between what the QR code
|
|
27
|
+
* told the authenticator app and what the server recomputed, so a test that
|
|
28
|
+
* stubs the verifier proves nothing about it. The secret is generated by the
|
|
29
|
+
* real service path, the code is produced by parsing the stored otpauth:// URI
|
|
30
|
+
* exactly as an authenticator app would, and the endpoint gets the real thing.
|
|
31
|
+
*
|
|
32
|
+
* The second concern is ownership. `id` comes from the request body, so
|
|
33
|
+
* without the userId comparison any signed-in user could mark a stranger's
|
|
34
|
+
* pending TOTP row as verified using a code from their own phone — a second
|
|
35
|
+
* factor the victim does not hold. That check is asserted directly, and the
|
|
36
|
+
* assertion that matters is that isVerified is never written.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
jest.mock("../../../Server/Utils/Express", () => {
|
|
40
|
+
return {
|
|
41
|
+
getRouter: () => {
|
|
42
|
+
return mockRouter;
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
jest.mock("../../../Server/Utils/Response", () => {
|
|
48
|
+
return {
|
|
49
|
+
sendEntityArrayResponse: jest.fn(),
|
|
50
|
+
sendJsonArrayResponse: jest.fn(),
|
|
51
|
+
sendJsonObjectResponse: jest.fn(),
|
|
52
|
+
sendEmptySuccessResponse: jest.fn(),
|
|
53
|
+
sendEntityResponse: jest.fn(),
|
|
54
|
+
sendErrorResponse: jest.fn(),
|
|
55
|
+
setNoCacheHeaders: jest.fn(),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
jest.mock("../../../Server/Services/UserTotpAuthService");
|
|
60
|
+
jest.mock("../../../Server/Services/UserService");
|
|
61
|
+
|
|
62
|
+
const VALIDATE_ROUTE: string = "/user-totp-auth/validate";
|
|
63
|
+
|
|
64
|
+
const TOTP_ID: ObjectID = new ObjectID("11111111-1111-4111-8111-111111111111");
|
|
65
|
+
const OWNER_ID: ObjectID = new ObjectID("22222222-2222-4222-8222-222222222222");
|
|
66
|
+
const ATTACKER_ID: ObjectID = new ObjectID(
|
|
67
|
+
"33333333-3333-4333-8333-333333333333",
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const OWNER_EMAIL: Email = new Email("owner@example.com");
|
|
71
|
+
|
|
72
|
+
type CallValidateResult = {
|
|
73
|
+
thrown: unknown;
|
|
74
|
+
nextCallCount: number;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
type CallValidateFunction = (data: {
|
|
78
|
+
body: Record<string, unknown>;
|
|
79
|
+
signedInUserId?: ObjectID | undefined;
|
|
80
|
+
}) => Promise<CallValidateResult>;
|
|
81
|
+
|
|
82
|
+
const callValidate: CallValidateFunction = async (data: {
|
|
83
|
+
body: Record<string, unknown>;
|
|
84
|
+
signedInUserId?: ObjectID | undefined;
|
|
85
|
+
}): Promise<CallValidateResult> => {
|
|
86
|
+
const req: OneUptimeRequest = {
|
|
87
|
+
body: data.body,
|
|
88
|
+
params: {},
|
|
89
|
+
query: {},
|
|
90
|
+
headers: {},
|
|
91
|
+
userAuthorization: {
|
|
92
|
+
userId: data.signedInUserId || OWNER_ID,
|
|
93
|
+
},
|
|
94
|
+
} as unknown as OneUptimeRequest;
|
|
95
|
+
|
|
96
|
+
const res: OneUptimeResponse = {
|
|
97
|
+
send: jest.fn(),
|
|
98
|
+
json: jest.fn(),
|
|
99
|
+
setHeader: jest.fn(),
|
|
100
|
+
status: jest.fn().mockReturnThis(),
|
|
101
|
+
} as unknown as OneUptimeResponse;
|
|
102
|
+
|
|
103
|
+
const next: NextFunction = jest.fn() as unknown as NextFunction;
|
|
104
|
+
|
|
105
|
+
await mockRouter
|
|
106
|
+
.match("post", VALIDATE_ROUTE)
|
|
107
|
+
.handlerFunction(req, res, next);
|
|
108
|
+
|
|
109
|
+
const nextMock: jest.Mock = next as unknown as jest.Mock;
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
thrown: nextMock.mock.calls[0]?.[0],
|
|
113
|
+
nextCallCount: nextMock.mock.calls.length,
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/*
|
|
118
|
+
* A pending enrolment, built the way the service builds one: a real secret and
|
|
119
|
+
* the real otpauth:// URI derived from it.
|
|
120
|
+
*/
|
|
121
|
+
type PendingEnrolmentFunction = (options?: { ownerId?: ObjectID }) => {
|
|
122
|
+
row: UserTotpAuth;
|
|
123
|
+
secret: string;
|
|
124
|
+
codeFromTheAuthenticatorApp: () => string;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const pendingEnrolment: PendingEnrolmentFunction = (options?: {
|
|
128
|
+
ownerId?: ObjectID;
|
|
129
|
+
}) => {
|
|
130
|
+
const secret: string = TotpAuth.generateSecret();
|
|
131
|
+
|
|
132
|
+
const otpUrl: string = TotpAuth.generateUri({
|
|
133
|
+
secret: secret,
|
|
134
|
+
userEmail: OWNER_EMAIL,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const row: UserTotpAuth = new UserTotpAuth();
|
|
138
|
+
row.id = TOTP_ID;
|
|
139
|
+
row.userId = options?.ownerId || OWNER_ID;
|
|
140
|
+
row.twoFactorSecret = secret;
|
|
141
|
+
row.twoFactorOtpUrl = otpUrl;
|
|
142
|
+
row.isVerified = false;
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
row: row,
|
|
146
|
+
secret: secret,
|
|
147
|
+
codeFromTheAuthenticatorApp: (): string => {
|
|
148
|
+
return (OTPAuth.URI.parse(otpUrl) as OTPAuth.TOTP).generate();
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
let findTotpById: jest.Mock;
|
|
154
|
+
let updateTotpById: jest.Mock;
|
|
155
|
+
let findUserById: jest.Mock;
|
|
156
|
+
|
|
157
|
+
describe("POST /user-totp-auth/validate", () => {
|
|
158
|
+
beforeEach(() => {
|
|
159
|
+
mockRouter.routes.length = 0;
|
|
160
|
+
|
|
161
|
+
findTotpById = jest.fn();
|
|
162
|
+
updateTotpById = jest.fn(async () => {
|
|
163
|
+
return undefined;
|
|
164
|
+
});
|
|
165
|
+
findUserById = jest.fn();
|
|
166
|
+
|
|
167
|
+
UserTotpAuthService.findOneById = findTotpById as never;
|
|
168
|
+
UserTotpAuthService.updateOneById = updateTotpById as never;
|
|
169
|
+
UserTotpAuthService.getModel = jest
|
|
170
|
+
.fn()
|
|
171
|
+
.mockReturnValue({ tableName: "UserTotpAuth" }) as never;
|
|
172
|
+
|
|
173
|
+
UserService.findOneById = findUserById as never;
|
|
174
|
+
|
|
175
|
+
const owner: User = new User();
|
|
176
|
+
owner.id = OWNER_ID;
|
|
177
|
+
owner.email = OWNER_EMAIL;
|
|
178
|
+
findUserById.mockResolvedValue(owner as never);
|
|
179
|
+
|
|
180
|
+
new UserTotpAuthAPI();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
afterEach(() => {
|
|
184
|
+
jest.restoreAllMocks();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe("the route itself", () => {
|
|
188
|
+
test("is registered as a POST", () => {
|
|
189
|
+
expect(() => {
|
|
190
|
+
return mockRouter.match("post", VALIDATE_ROUTE);
|
|
191
|
+
}).not.toThrow();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
/*
|
|
195
|
+
* Without an authentication middleware the handler would read
|
|
196
|
+
* `userAuthorization` off an unauthenticated request, the ownership
|
|
197
|
+
* comparison below would compare against `undefined`, and anybody could
|
|
198
|
+
* verify anybody's TOTP row.
|
|
199
|
+
*/
|
|
200
|
+
test("is behind an authentication middleware", () => {
|
|
201
|
+
expect(mockRouter.match("post", VALIDATE_ROUTE).middlewares.length).toBe(
|
|
202
|
+
1,
|
|
203
|
+
);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe("when the code is the one the user's app is showing", () => {
|
|
208
|
+
test("marks the enrolment verified", async () => {
|
|
209
|
+
const enrolment: ReturnType<PendingEnrolmentFunction> =
|
|
210
|
+
pendingEnrolment();
|
|
211
|
+
|
|
212
|
+
findTotpById.mockResolvedValue(enrolment.row as never);
|
|
213
|
+
|
|
214
|
+
const result: CallValidateResult = await callValidate({
|
|
215
|
+
body: {
|
|
216
|
+
id: TOTP_ID.toString(),
|
|
217
|
+
code: enrolment.codeFromTheAuthenticatorApp(),
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
expect(result.thrown).toBeUndefined();
|
|
222
|
+
|
|
223
|
+
expect(updateTotpById).toHaveBeenCalledWith(
|
|
224
|
+
expect.objectContaining({
|
|
225
|
+
id: TOTP_ID,
|
|
226
|
+
data: { isVerified: true },
|
|
227
|
+
}),
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
expect(Response.sendEmptySuccessResponse).toHaveBeenCalled();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
/*
|
|
234
|
+
* Google Authenticator renders the code as "123 456" and the phone
|
|
235
|
+
* clipboard keeps the space. This is the same enrolment, pasted.
|
|
236
|
+
*/
|
|
237
|
+
test("accepts the code as the phone's clipboard hands it over", async () => {
|
|
238
|
+
const enrolment: ReturnType<PendingEnrolmentFunction> =
|
|
239
|
+
pendingEnrolment();
|
|
240
|
+
|
|
241
|
+
findTotpById.mockResolvedValue(enrolment.row as never);
|
|
242
|
+
|
|
243
|
+
const code: string = enrolment.codeFromTheAuthenticatorApp();
|
|
244
|
+
|
|
245
|
+
const result: CallValidateResult = await callValidate({
|
|
246
|
+
body: {
|
|
247
|
+
id: TOTP_ID.toString(),
|
|
248
|
+
code: `${code.slice(0, 3)} ${code.slice(3)}`,
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
expect(result.thrown).toBeUndefined();
|
|
253
|
+
expect(updateTotpById).toHaveBeenCalled();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test("reads the secret with root privileges, since the column is unreadable otherwise", async () => {
|
|
257
|
+
const enrolment: ReturnType<PendingEnrolmentFunction> =
|
|
258
|
+
pendingEnrolment();
|
|
259
|
+
|
|
260
|
+
findTotpById.mockResolvedValue(enrolment.row as never);
|
|
261
|
+
|
|
262
|
+
await callValidate({
|
|
263
|
+
body: {
|
|
264
|
+
id: TOTP_ID.toString(),
|
|
265
|
+
code: enrolment.codeFromTheAuthenticatorApp(),
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
expect(findTotpById).toHaveBeenCalledWith(
|
|
270
|
+
expect.objectContaining({
|
|
271
|
+
select: expect.objectContaining({ twoFactorSecret: true }),
|
|
272
|
+
props: { isRoot: true },
|
|
273
|
+
}),
|
|
274
|
+
);
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
describe("when the code is wrong", () => {
|
|
279
|
+
test("fails with Invalid code and leaves the enrolment unverified", async () => {
|
|
280
|
+
const enrolment: ReturnType<PendingEnrolmentFunction> =
|
|
281
|
+
pendingEnrolment();
|
|
282
|
+
|
|
283
|
+
findTotpById.mockResolvedValue(enrolment.row as never);
|
|
284
|
+
|
|
285
|
+
const result: CallValidateResult = await callValidate({
|
|
286
|
+
body: { id: TOTP_ID.toString(), code: "000000" },
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
expect(result.thrown).toBeInstanceOf(BadDataException);
|
|
290
|
+
expect((result.thrown as Exception).message).toBe("Invalid code");
|
|
291
|
+
expect(updateTotpById).not.toHaveBeenCalled();
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test.each([
|
|
295
|
+
["a missing code", undefined],
|
|
296
|
+
["an empty code", ""],
|
|
297
|
+
["a truncated code", "1234"],
|
|
298
|
+
])(
|
|
299
|
+
"rejects %s without verifying anything",
|
|
300
|
+
async (_name: string, code: string | undefined) => {
|
|
301
|
+
const enrolment: ReturnType<PendingEnrolmentFunction> =
|
|
302
|
+
pendingEnrolment();
|
|
303
|
+
|
|
304
|
+
findTotpById.mockResolvedValue(enrolment.row as never);
|
|
305
|
+
|
|
306
|
+
const result: CallValidateResult = await callValidate({
|
|
307
|
+
body: { id: TOTP_ID.toString(), code: code },
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
expect(result.thrown).toBeInstanceOf(BadDataException);
|
|
311
|
+
expect(updateTotpById).not.toHaveBeenCalled();
|
|
312
|
+
},
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
/*
|
|
316
|
+
* A code that is valid for a DIFFERENT enrolment. This is what an attacker
|
|
317
|
+
* with their own authenticator would submit.
|
|
318
|
+
*/
|
|
319
|
+
test("rejects a code that is valid for somebody else's secret", async () => {
|
|
320
|
+
const victim: ReturnType<PendingEnrolmentFunction> = pendingEnrolment();
|
|
321
|
+
const attacker: ReturnType<PendingEnrolmentFunction> = pendingEnrolment();
|
|
322
|
+
|
|
323
|
+
findTotpById.mockResolvedValue(victim.row as never);
|
|
324
|
+
|
|
325
|
+
const result: CallValidateResult = await callValidate({
|
|
326
|
+
body: {
|
|
327
|
+
id: TOTP_ID.toString(),
|
|
328
|
+
code: attacker.codeFromTheAuthenticatorApp(),
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
expect(result.thrown).toBeInstanceOf(BadDataException);
|
|
333
|
+
expect(updateTotpById).not.toHaveBeenCalled();
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
describe("ownership", () => {
|
|
338
|
+
/*
|
|
339
|
+
* `id` is attacker-controlled. If the handler stopped comparing userId, a
|
|
340
|
+
* signed-in attacker could point this endpoint at any pending enrolment in
|
|
341
|
+
* the database and verify it with a code from their own phone.
|
|
342
|
+
*/
|
|
343
|
+
test("refuses to verify an enrolment belonging to another user", async () => {
|
|
344
|
+
const enrolment: ReturnType<PendingEnrolmentFunction> = pendingEnrolment({
|
|
345
|
+
ownerId: OWNER_ID,
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
findTotpById.mockResolvedValue(enrolment.row as never);
|
|
349
|
+
|
|
350
|
+
const result: CallValidateResult = await callValidate({
|
|
351
|
+
body: {
|
|
352
|
+
id: TOTP_ID.toString(),
|
|
353
|
+
code: enrolment.codeFromTheAuthenticatorApp(),
|
|
354
|
+
},
|
|
355
|
+
signedInUserId: ATTACKER_ID,
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
expect(result.thrown).toBeInstanceOf(BadDataException);
|
|
359
|
+
expect(updateTotpById).not.toHaveBeenCalled();
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
test("does not reveal that the enrolment exists", async () => {
|
|
363
|
+
const enrolment: ReturnType<PendingEnrolmentFunction> = pendingEnrolment({
|
|
364
|
+
ownerId: OWNER_ID,
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
findTotpById.mockResolvedValue(enrolment.row as never);
|
|
368
|
+
|
|
369
|
+
const result: CallValidateResult = await callValidate({
|
|
370
|
+
body: {
|
|
371
|
+
id: TOTP_ID.toString(),
|
|
372
|
+
code: enrolment.codeFromTheAuthenticatorApp(),
|
|
373
|
+
},
|
|
374
|
+
signedInUserId: ATTACKER_ID,
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
expect((result.thrown as Exception).message).toBe(
|
|
378
|
+
"Two factor auth not found",
|
|
379
|
+
);
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
describe("when the record is not usable", () => {
|
|
384
|
+
test("fails when no such enrolment exists", async () => {
|
|
385
|
+
findTotpById.mockResolvedValue(null as never);
|
|
386
|
+
|
|
387
|
+
const result: CallValidateResult = await callValidate({
|
|
388
|
+
body: { id: TOTP_ID.toString(), code: "123456" },
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
expect(result.thrown).toBeInstanceOf(BadDataException);
|
|
392
|
+
expect(updateTotpById).not.toHaveBeenCalled();
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
test("fails when the owning user has no email to label the entry with", async () => {
|
|
396
|
+
const enrolment: ReturnType<PendingEnrolmentFunction> =
|
|
397
|
+
pendingEnrolment();
|
|
398
|
+
|
|
399
|
+
findTotpById.mockResolvedValue(enrolment.row as never);
|
|
400
|
+
|
|
401
|
+
const emailless: User = new User();
|
|
402
|
+
emailless.id = OWNER_ID;
|
|
403
|
+
findUserById.mockResolvedValue(emailless as never);
|
|
404
|
+
|
|
405
|
+
const result: CallValidateResult = await callValidate({
|
|
406
|
+
body: {
|
|
407
|
+
id: TOTP_ID.toString(),
|
|
408
|
+
code: enrolment.codeFromTheAuthenticatorApp(),
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
expect(result.thrown).toBeInstanceOf(BadDataException);
|
|
413
|
+
expect(updateTotpById).not.toHaveBeenCalled();
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
test("surfaces the failure through next() rather than crashing the request", async () => {
|
|
417
|
+
findTotpById.mockRejectedValue(new Error("database is on fire") as never);
|
|
418
|
+
|
|
419
|
+
const result: CallValidateResult = await callValidate({
|
|
420
|
+
body: { id: TOTP_ID.toString(), code: "123456" },
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
expect(result.nextCallCount).toBe(1);
|
|
424
|
+
expect(result.thrown).toBeInstanceOf(Error);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import InMemoryTTLCache from "../../../Server/Infrastructure/InMemoryTTLCache";
|
|
2
|
+
import { afterEach, describe, expect, jest, test } from "@jest/globals";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Contract under test — the bounded TTL cache the telemetry ingest rule
|
|
6
|
+
* caches (log/trace pipelines, drop filters, scrub rules, metric rules)
|
|
7
|
+
* sit on. Two properties matter for those callers:
|
|
8
|
+
*
|
|
9
|
+
* 1. Expiry physically deletes: a read past the TTL must both miss AND
|
|
10
|
+
* shrink the store, or per-project entries accumulate for every tenant
|
|
11
|
+
* ever seen by a long-lived ingest process.
|
|
12
|
+
* 2. Capacity is a hard cap with oldest-write eviction, so the cache can
|
|
13
|
+
* never grow past maxEntries no matter how many distinct keys arrive.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/*
|
|
17
|
+
* Minimal structural view of a jest spy — the @jest/globals and @types/jest
|
|
18
|
+
* spy types disagree in this repo, so annotate with just the surface these
|
|
19
|
+
* tests use.
|
|
20
|
+
*/
|
|
21
|
+
type NowSpyLike = {
|
|
22
|
+
mockReturnValue: (value: number) => unknown;
|
|
23
|
+
mockRestore: () => void;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function spyNow(value: number): NowSpyLike {
|
|
27
|
+
const spy: NowSpyLike = jest.spyOn(Date, "now") as unknown as NowSpyLike;
|
|
28
|
+
spy.mockReturnValue(value);
|
|
29
|
+
return spy;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
jest.restoreAllMocks();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe("InMemoryTTLCache TTL behavior", () => {
|
|
37
|
+
test("get returns the value within its TTL", () => {
|
|
38
|
+
const cache: InMemoryTTLCache<string> = new InMemoryTTLCache<string>(3);
|
|
39
|
+
|
|
40
|
+
cache.set("a", "value-a", 60_000);
|
|
41
|
+
|
|
42
|
+
expect(cache.get("a")).toBe("value-a");
|
|
43
|
+
expect(cache.has("a")).toBe(true);
|
|
44
|
+
expect(cache.size()).toBe(1);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("get past the TTL misses AND physically deletes the entry", () => {
|
|
48
|
+
const t0: number = 1_000_000;
|
|
49
|
+
const nowSpy: NowSpyLike = spyNow(t0);
|
|
50
|
+
|
|
51
|
+
const cache: InMemoryTTLCache<string> = new InMemoryTTLCache<string>(3);
|
|
52
|
+
cache.set("a", "value-a", 1_000);
|
|
53
|
+
expect(cache.size()).toBe(1);
|
|
54
|
+
|
|
55
|
+
// Boundary: at exactly expiresAt the entry is still valid (strict >).
|
|
56
|
+
nowSpy.mockReturnValue(t0 + 1_000);
|
|
57
|
+
expect(cache.get("a")).toBe("value-a");
|
|
58
|
+
expect(cache.size()).toBe(1);
|
|
59
|
+
|
|
60
|
+
nowSpy.mockReturnValue(t0 + 1_001);
|
|
61
|
+
expect(cache.get("a")).toBeUndefined();
|
|
62
|
+
expect(cache.size()).toBe(0);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("has() reports false for an expired entry and deletes it", () => {
|
|
66
|
+
const t0: number = 1_000_000;
|
|
67
|
+
const nowSpy: NowSpyLike = spyNow(t0);
|
|
68
|
+
|
|
69
|
+
const cache: InMemoryTTLCache<string> = new InMemoryTTLCache<string>(3);
|
|
70
|
+
cache.set("a", "value-a", 1_000);
|
|
71
|
+
|
|
72
|
+
nowSpy.mockReturnValue(t0 + 5_000);
|
|
73
|
+
expect(cache.has("a")).toBe(false);
|
|
74
|
+
expect(cache.size()).toBe(0);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe("InMemoryTTLCache capacity eviction", () => {
|
|
79
|
+
test("insert beyond capacity evicts the oldest key", () => {
|
|
80
|
+
const cache: InMemoryTTLCache<string> = new InMemoryTTLCache<string>(3);
|
|
81
|
+
|
|
82
|
+
cache.set("a", "value-a", 60_000);
|
|
83
|
+
cache.set("b", "value-b", 60_000);
|
|
84
|
+
cache.set("c", "value-c", 60_000);
|
|
85
|
+
cache.set("d", "value-d", 60_000);
|
|
86
|
+
|
|
87
|
+
expect(cache.size()).toBe(3);
|
|
88
|
+
expect(cache.get("a")).toBeUndefined();
|
|
89
|
+
expect(cache.get("b")).toBe("value-b");
|
|
90
|
+
expect(cache.get("c")).toBe("value-c");
|
|
91
|
+
expect(cache.get("d")).toBe("value-d");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("re-setting an existing key refreshes insertion order so it is not the eviction victim", () => {
|
|
95
|
+
const cache: InMemoryTTLCache<string> = new InMemoryTTLCache<string>(3);
|
|
96
|
+
|
|
97
|
+
cache.set("a", "value-a", 60_000);
|
|
98
|
+
cache.set("b", "value-b", 60_000);
|
|
99
|
+
cache.set("c", "value-c", 60_000);
|
|
100
|
+
|
|
101
|
+
// Overwrite at capacity: no eviction, "a" moves to newest position.
|
|
102
|
+
cache.set("a", "value-a2", 60_000);
|
|
103
|
+
expect(cache.size()).toBe(3);
|
|
104
|
+
expect(cache.get("b")).toBe("value-b");
|
|
105
|
+
expect(cache.get("c")).toBe("value-c");
|
|
106
|
+
|
|
107
|
+
// Next new key evicts "b" (now the oldest), not the refreshed "a".
|
|
108
|
+
cache.set("d", "value-d", 60_000);
|
|
109
|
+
expect(cache.size()).toBe(3);
|
|
110
|
+
expect(cache.get("a")).toBe("value-a2");
|
|
111
|
+
expect(cache.get("b")).toBeUndefined();
|
|
112
|
+
expect(cache.get("c")).toBe("value-c");
|
|
113
|
+
expect(cache.get("d")).toBe("value-d");
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("InMemoryTTLCache basics", () => {
|
|
118
|
+
test("values are stored by reference", () => {
|
|
119
|
+
const cache: InMemoryTTLCache<Array<string>> = new InMemoryTTLCache<
|
|
120
|
+
Array<string>
|
|
121
|
+
>(3);
|
|
122
|
+
|
|
123
|
+
const value: Array<string> = [];
|
|
124
|
+
cache.set("a", value, 60_000);
|
|
125
|
+
|
|
126
|
+
expect(cache.get("a")).toBe(value);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("delete removes an entry", () => {
|
|
130
|
+
const cache: InMemoryTTLCache<string> = new InMemoryTTLCache<string>(3);
|
|
131
|
+
|
|
132
|
+
cache.set("a", "value-a", 60_000);
|
|
133
|
+
cache.delete("a");
|
|
134
|
+
|
|
135
|
+
expect(cache.get("a")).toBeUndefined();
|
|
136
|
+
expect(cache.has("a")).toBe(false);
|
|
137
|
+
expect(cache.size()).toBe(0);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("clear empties the cache", () => {
|
|
141
|
+
const cache: InMemoryTTLCache<string> = new InMemoryTTLCache<string>(3);
|
|
142
|
+
|
|
143
|
+
cache.set("a", "value-a", 60_000);
|
|
144
|
+
cache.set("b", "value-b", 60_000);
|
|
145
|
+
cache.clear();
|
|
146
|
+
|
|
147
|
+
expect(cache.size()).toBe(0);
|
|
148
|
+
expect(cache.get("a")).toBeUndefined();
|
|
149
|
+
expect(cache.get("b")).toBeUndefined();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("has returns false for a key that was never set", () => {
|
|
153
|
+
const cache: InMemoryTTLCache<string> = new InMemoryTTLCache<string>(3);
|
|
154
|
+
|
|
155
|
+
expect(cache.has("missing")).toBe(false);
|
|
156
|
+
expect(cache.get("missing")).toBeUndefined();
|
|
157
|
+
});
|
|
158
|
+
});
|
package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts
CHANGED
|
@@ -20,16 +20,14 @@ import { AddDeviceRoleAndDeclaredLinkParent1787400000000 } from "../../../../Ser
|
|
|
20
20
|
* either would silently restate every device and every link in every
|
|
21
21
|
* project as something an operator had chosen.
|
|
22
22
|
*
|
|
23
|
-
* The second is
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* Whoever adds the next migration should move this test's ordering block
|
|
32
|
-
* to theirs.
|
|
23
|
+
* The second is REGISTRATION: an import that never reaches the default
|
|
24
|
+
* export array leaves the migration unregistered, and it silently never
|
|
25
|
+
* runs.
|
|
26
|
+
*
|
|
27
|
+
* The ordering guard this file used to carry — "this is the newest
|
|
28
|
+
* migration, so its timestamp must sort above every other" — has moved on
|
|
29
|
+
* to AddNetworkDeviceReachabilityColumnsMigration.test.ts, which is now the
|
|
30
|
+
* newest. Whoever adds the next migration should move it again.
|
|
33
31
|
*/
|
|
34
32
|
|
|
35
33
|
const MIGRATION_PATH: string = path.join(
|
|
@@ -39,15 +37,6 @@ const MIGRATION_PATH: string = path.join(
|
|
|
39
37
|
|
|
40
38
|
const SOURCE: string = fs.readFileSync(MIGRATION_PATH, "utf8");
|
|
41
39
|
|
|
42
|
-
interface MigrationClass {
|
|
43
|
-
name: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function timestampOf(migrationClass: MigrationClass): number | null {
|
|
47
|
-
const match: RegExpMatchArray | null = migrationClass.name.match(/(\d+)$/);
|
|
48
|
-
return match ? Number(match[1]) : null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
40
|
describe("the columns it adds", () => {
|
|
52
41
|
test("NetworkDevice gains deviceRole", () => {
|
|
53
42
|
expect(SOURCE).toContain(
|
|
@@ -190,50 +179,10 @@ describe("the migration runs", () => {
|
|
|
190
179
|
);
|
|
191
180
|
});
|
|
192
181
|
|
|
193
|
-
// The guard described in the header. Hand it to the next migration.
|
|
194
|
-
test("its timestamp sorts after every other registered migration", () => {
|
|
195
|
-
const ourTimestamp: number | null = timestampOf(
|
|
196
|
-
AddDeviceRoleAndDeclaredLinkParent1787400000000,
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
expect(ourTimestamp).not.toBeNull();
|
|
200
|
-
|
|
201
|
-
const otherTimestamps: Array<number> = [];
|
|
202
|
-
|
|
203
|
-
for (const migrationClass of SchemaMigrations) {
|
|
204
|
-
if (migrationClass === AddDeviceRoleAndDeclaredLinkParent1787400000000) {
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const timestamp: number | null = timestampOf(
|
|
209
|
-
migrationClass as MigrationClass,
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
if (timestamp !== null) {
|
|
213
|
-
otherTimestamps.push(timestamp);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/*
|
|
218
|
-
* Math.max() of an empty list is -Infinity, which every timestamp beats.
|
|
219
|
-
* Prove the list was actually enumerated before leaning on the maximum.
|
|
220
|
-
*/
|
|
221
|
-
expect(otherTimestamps.length).toBeGreaterThan(100);
|
|
222
|
-
|
|
223
|
-
expect(ourTimestamp).toBeGreaterThan(Math.max(...otherTimestamps));
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
test("it is registered last, matching that timestamp", () => {
|
|
227
|
-
expect(SchemaMigrations[SchemaMigrations.length - 1]).toBe(
|
|
228
|
-
AddDeviceRoleAndDeclaredLinkParent1787400000000,
|
|
229
|
-
);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
182
|
/*
|
|
233
183
|
* ...and the timestamp in the class name is the one on disk. A class
|
|
234
184
|
* renamed without renaming its file (or two migrations landing on the
|
|
235
|
-
* same timestamp)
|
|
236
|
-
* not what actually runs.
|
|
185
|
+
* same timestamp) runs in an order nobody declared.
|
|
237
186
|
*/
|
|
238
187
|
test("exactly one file on disk carries its timestamp, and it is this one", () => {
|
|
239
188
|
const directory: string = path.dirname(MIGRATION_PATH);
|