@oneuptime/common 12.0.2 → 12.0.4
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/CephCluster.ts +14 -0
- package/Models/DatabaseModels/CodeRepository.ts +14 -6
- package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
- package/Models/DatabaseModels/DockerHost.ts +14 -0
- package/Models/DatabaseModels/GlobalOidcProject.ts +18 -0
- package/Models/DatabaseModels/GlobalSsoProject.ts +18 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/IoTFleet.ts +14 -0
- package/Models/DatabaseModels/KubernetesCluster.ts +14 -0
- package/Models/DatabaseModels/LogDropFilter.ts +9 -20
- package/Models/DatabaseModels/NetworkDevice.ts +14 -0
- package/Models/DatabaseModels/NetworkInterface.ts +18 -0
- package/Models/DatabaseModels/Project.ts +16 -2
- package/Models/DatabaseModels/ProxmoxCluster.ts +14 -0
- package/Models/DatabaseModels/Service.ts +30 -0
- package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
- package/Models/DatabaseModels/StatusPagePrivateUser.ts +30 -0
- package/Models/DatabaseModels/StatusPageResource.ts +73 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
- package/Models/DatabaseModels/User.ts +30 -0
- package/Server/API/AIAgentDataAPI.ts +31 -0
- package/Server/API/BaseAPI.ts +13 -2
- package/Server/API/DashboardAPI.ts +458 -12
- package/Server/API/GitHubAPI.ts +119 -283
- package/Server/API/UserAPI.ts +263 -1
- package/Server/EnvironmentConfig.ts +38 -4
- package/Server/Infrastructure/GlobalCache.ts +152 -0
- package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.ts +21 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.ts +68 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +100 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +214 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.ts +69 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Services/AlertStateTimelineService.ts +20 -0
- package/Server/Services/AnalyticsDatabaseService.ts +72 -1
- package/Server/Services/CephClusterService.ts +26 -86
- package/Server/Services/CloudResourceService.ts +23 -83
- package/Server/Services/CodeRepositoryService.ts +105 -2
- package/Server/Services/DatabaseService.ts +296 -2
- package/Server/Services/DockerHostService.ts +19 -79
- package/Server/Services/DockerSwarmClusterService.ts +27 -88
- package/Server/Services/HostService.ts +46 -99
- package/Server/Services/IncidentStateTimelineService.ts +20 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTFleetService.ts +19 -79
- package/Server/Services/KubernetesClusterService.ts +17 -78
- package/Server/Services/LabelService.ts +57 -10
- package/Server/Services/MetricTypeService.ts +84 -0
- package/Server/Services/MonitorService.ts +89 -14
- package/Server/Services/MonitorStatusTimelineService.ts +29 -0
- package/Server/Services/MonitorTemplateService.ts +65 -0
- package/Server/Services/OpenTelemetryIngestService.ts +230 -26
- package/Server/Services/PodmanHostService.ts +19 -79
- package/Server/Services/ProxmoxClusterService.ts +23 -83
- package/Server/Services/RumApplicationService.ts +19 -80
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
- package/Server/Services/ServerlessFunctionService.ts +24 -85
- package/Server/Services/ServiceService.ts +299 -73
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
- package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
- package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
- package/Server/Services/TelemetryEntityService.ts +1 -0
- package/Server/Services/UserService.ts +184 -0
- package/Server/Utils/AI/Toolbox/CodeTools.ts +45 -4
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +13 -0
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +157 -4
- package/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.ts +130 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
- package/Server/Utils/Monitor/MonitorResource.ts +63 -36
- package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
- package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
- package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
- package/Server/Utils/PasswordHash.ts +306 -0
- package/Server/Utils/SingleFlight.ts +83 -0
- package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
- package/Server/Utils/Telemetry/Telemetry.ts +351 -122
- package/Tests/App/Dashboard/OverviewCustomFields.test.tsx +333 -0
- package/Tests/App/Dashboard/UserCustomFields.test.tsx +392 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
- package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
- package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
- package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
- package/Tests/Server/API/AIAgentDataRepositoryToken.test.ts +381 -0
- package/Tests/Server/API/DashboardPublicAttributeValuesAPI.test.ts +943 -0
- package/Tests/Server/API/DashboardPublicMetricsAggregateAPI.test.ts +1296 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
- package/Tests/Server/API/DashboardPublicTemplatePayloads.test.ts +598 -0
- package/Tests/Server/API/GitHubAppInstallationBindingAPI.test.ts +539 -0
- package/Tests/Server/API/Helpers.ts +6 -1
- package/Tests/Server/API/UserProjectsAPI.test.ts +852 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +354 -0
- package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
- package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +215 -0
- package/Tests/Server/Services/AddPerUserPasswordSaltMigration.test.ts +178 -0
- package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +582 -0
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +5 -0
- package/Tests/Server/Services/CodeRepositoryInstallationBinding.test.ts +305 -0
- package/Tests/Server/Services/CodeRepositoryResolutionBinding.test.ts +147 -0
- package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +870 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +163 -15
- package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
- package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
- package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
- package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +568 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +305 -56
- package/Tests/Server/Services/RestoreDroppedUniqueIndexesMigration.test.ts +386 -0
- package/Tests/Server/Services/RestoreServiceLowerNameIndexMigration.test.ts +240 -0
- package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
- package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
- package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
- package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
- package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +885 -0
- package/Tests/Server/Services/WidenHashedStringColumnsForScryptMigration.test.ts +220 -0
- package/Tests/Server/Utils/AI/CodeTools.test.ts +47 -1
- package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +10 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +120 -0
- package/Tests/Server/Utils/CodeRepository/GitHubInstallationBinding.test.ts +292 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
- package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
- package/Tests/Server/Utils/GitHubInstallationOwnershipVerification.test.ts +340 -0
- package/Tests/Server/Utils/GitHubWebhookAndTreeCacheIsolation.test.ts +250 -0
- package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
- package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
- package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
- package/Tests/Server/Utils/PasswordHash.test.ts +555 -0
- package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
- package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
- package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
- package/Tests/Types/Database/ColumnLength.test.ts +7 -1
- package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
- package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
- package/Tests/Types/Decimal.test.ts +37 -0
- package/Tests/Types/HashedStringPerUserSalt.test.ts +476 -0
- package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +293 -0
- package/Tests/Types/Monitor/HostAlertTemplates.test.ts +249 -0
- package/Tests/Types/Monitor/IotAlertTemplates.test.ts +320 -0
- package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +271 -0
- package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
- package/Tests/Types/Port.test.ts +38 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +696 -0
- package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
- package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
- package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
- package/Tests/UI/Utils/UserProjectsModelAPI.test.ts +714 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
- package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
- package/Tests/Utils/TeamMembersByProject.test.ts +655 -0
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
- package/Types/Dashboard/DashboardTemplates.ts +397 -0
- package/Types/Database/BigIntColumnTransformer.ts +74 -0
- package/Types/Database/ColumnLength.ts +9 -1
- package/Types/Database/DatabaseProperty.ts +26 -0
- package/Types/Database/NumericColumnValue.ts +128 -0
- package/Types/Database/TableColumn.ts +11 -0
- package/Types/Database/UnsynchronizedIndex.ts +48 -0
- package/Types/Decimal.ts +16 -4
- package/Types/HashedString.ts +139 -4
- package/Types/Permission.ts +48 -0
- package/Types/Port.ts +16 -4
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +85 -11
- package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
- package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
- package/UI/Components/Navbar/NavBar.tsx +12 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +19 -7
- package/UI/Utils/ModelAPI/UserProjectsModelAPI.ts +257 -0
- package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/TeamMembersByProject.ts +237 -0
- package/build/dist/Models/DatabaseModels/CephCluster.js +16 -1
- package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CodeRepository.js +14 -6
- package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +16 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +16 -1
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +16 -1
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IoTFleet.js +16 -1
- package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +16 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +16 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkInterface.js +16 -1
- package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +16 -2
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +16 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Service.js +28 -1
- package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +32 -0
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
- package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +32 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +21 -2
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +11 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +343 -10
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/GitHubAPI.js +94 -167
- package/build/dist/Server/API/GitHubAPI.js.map +1 -1
- package/build/dist/Server/API/UserAPI.js +187 -2
- package/build/dist/Server/API/UserAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +34 -4
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/GlobalCache.js +120 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js +59 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +93 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js +101 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js +66 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +57 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterService.js +26 -76
- package/build/dist/Server/Services/CephClusterService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceService.js +23 -73
- package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
- package/build/dist/Server/Services/CodeRepositoryService.js +90 -2
- package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +246 -2
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +19 -69
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -78
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +58 -102
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetService.js +19 -69
- package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterService.js +17 -68
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/LabelService.js +42 -7
- package/build/dist/Server/Services/LabelService.js.map +1 -1
- package/build/dist/Server/Services/MetricTypeService.js +74 -0
- package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +81 -9
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +155 -25
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostService.js +19 -69
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterService.js +23 -73
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationService.js +19 -70
- package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionService.js +24 -75
- package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +236 -61
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +165 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +31 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +13 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +126 -4
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js +136 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js.map +1 -0
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
- package/build/dist/Server/Utils/PasswordHash.js +237 -0
- package/build/dist/Server/Utils/PasswordHash.js.map +1 -0
- package/build/dist/Server/Utils/SingleFlight.js +76 -0
- package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
- package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
- package/build/dist/Types/Database/ColumnLength.js +9 -1
- package/build/dist/Types/Database/ColumnLength.js.map +1 -1
- package/build/dist/Types/Database/DatabaseProperty.js +25 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/NumericColumnValue.js +97 -0
- package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/Database/UnsynchronizedIndex.js +46 -0
- package/build/dist/Types/Database/UnsynchronizedIndex.js.map +1 -0
- package/build/dist/Types/Decimal.js +14 -3
- package/build/dist/Types/Decimal.js.map +1 -1
- package/build/dist/Types/HashedString.js +95 -5
- package/build/dist/Types/HashedString.js.map +1 -1
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Port.js +15 -5
- package/build/dist/Types/Port.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +51 -10
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
- package/build/dist/UI/Components/Navbar/NavBar.js +3 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +19 -7
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js +156 -0
- package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/TeamMembersByProject.js +145 -0
- package/build/dist/Utils/TeamMembersByProject.js.map +1 -0
- package/package.json +1 -1
package/Server/API/UserAPI.ts
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
|
+
import Team from "../../Models/DatabaseModels/Team";
|
|
2
|
+
import TeamMember from "../../Models/DatabaseModels/TeamMember";
|
|
1
3
|
import User from "../../Models/DatabaseModels/User";
|
|
4
|
+
import BaseModel from "../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
|
5
|
+
import Query from "../../Types/BaseDatabase/Query";
|
|
6
|
+
import LIMIT_MAX, { DEFAULT_LIMIT } from "../../Types/Database/LimitMax";
|
|
7
|
+
import BadDataException from "../../Types/Exception/BadDataException";
|
|
2
8
|
import NotFoundException from "../../Types/Exception/NotFoundException";
|
|
9
|
+
import { JSONArray, JSONObject } from "../../Types/JSON";
|
|
3
10
|
import ObjectID from "../../Types/ObjectID";
|
|
11
|
+
import PositiveNumber from "../../Types/PositiveNumber";
|
|
12
|
+
import TeamMembersByProject, {
|
|
13
|
+
UserProjectMembership,
|
|
14
|
+
} from "../../Utils/TeamMembersByProject";
|
|
15
|
+
import MasterAdminAuthorization from "../Middleware/MasterAdminAuthorization";
|
|
16
|
+
import TeamMemberService from "../Services/TeamMemberService";
|
|
4
17
|
import UserService, {
|
|
5
18
|
Service as UserServiceType,
|
|
6
19
|
} from "../Services/UserService";
|
|
7
|
-
import
|
|
20
|
+
import CommonAPI from "./CommonAPI";
|
|
21
|
+
import DatabaseCommonInteractionProps from "../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
22
|
+
import {
|
|
23
|
+
ExpressRequest,
|
|
24
|
+
ExpressResponse,
|
|
25
|
+
NextFunction,
|
|
26
|
+
} from "../Utils/Express";
|
|
8
27
|
import logger, { getLogAttributesFromRequest } from "../Utils/Logger";
|
|
9
28
|
import Response from "../Utils/Response";
|
|
10
29
|
import BaseAPI from "./BaseAPI";
|
|
@@ -16,6 +35,162 @@ export default class UserAPI extends BaseAPI<User, UserServiceType> {
|
|
|
16
35
|
public constructor() {
|
|
17
36
|
super(User, UserService);
|
|
18
37
|
|
|
38
|
+
/*
|
|
39
|
+
* Every project one user belongs to, one row per project, for the Admin
|
|
40
|
+
* Dashboard's User > Projects page.
|
|
41
|
+
*
|
|
42
|
+
* There is no CRUD list that answers this. `GET /team-member` scoped to a
|
|
43
|
+
* user returns MEMBERSHIPS - a (user, team) pair - so a user on three teams
|
|
44
|
+
* of one project comes back as three rows and reads as three projects. This
|
|
45
|
+
* endpoint folds those into one row per project carrying every team the
|
|
46
|
+
* user is on there, which is both what the page renders and what any
|
|
47
|
+
* caller asking "which projects is this person in?" actually wants.
|
|
48
|
+
*
|
|
49
|
+
* Master-admin only: it deliberately reads across every tenant, which is
|
|
50
|
+
* exactly what no project-scoped caller is allowed to do. The middleware is
|
|
51
|
+
* the gate; the read below runs as root because a master admin is not a
|
|
52
|
+
* member of the projects being listed and so has no tenant permissions to
|
|
53
|
+
* read them with.
|
|
54
|
+
*/
|
|
55
|
+
this.router.post(
|
|
56
|
+
`${new this.entityType().getCrudApiPath()?.toString()}/:userId/projects`,
|
|
57
|
+
MasterAdminAuthorization.isAuthorizedMasterAdminMiddleware,
|
|
58
|
+
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
59
|
+
try {
|
|
60
|
+
const userId: ObjectID = UserAPI.getUserIdFromParams(req);
|
|
61
|
+
|
|
62
|
+
const memberships: Array<TeamMember> = await TeamMemberService.findBy(
|
|
63
|
+
{
|
|
64
|
+
query: {
|
|
65
|
+
userId: userId,
|
|
66
|
+
},
|
|
67
|
+
select: {
|
|
68
|
+
_id: true,
|
|
69
|
+
projectId: true,
|
|
70
|
+
teamId: true,
|
|
71
|
+
hasAcceptedInvitation: true,
|
|
72
|
+
createdAt: true,
|
|
73
|
+
project: {
|
|
74
|
+
_id: true,
|
|
75
|
+
name: true,
|
|
76
|
+
slug: true,
|
|
77
|
+
},
|
|
78
|
+
team: {
|
|
79
|
+
_id: true,
|
|
80
|
+
name: true,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
limit: LIMIT_MAX,
|
|
84
|
+
skip: 0,
|
|
85
|
+
sort: {},
|
|
86
|
+
props: {
|
|
87
|
+
isRoot: true,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const rows: Array<UserProjectMembership> =
|
|
93
|
+
TeamMembersByProject.sortByProjectName(
|
|
94
|
+
TeamMembersByProject.groupByProject(memberships),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const skip: number = UserAPI.getPositiveIntegerParam(
|
|
98
|
+
req.query["skip"],
|
|
99
|
+
0,
|
|
100
|
+
);
|
|
101
|
+
const limit: number = UserAPI.getPositiveIntegerParam(
|
|
102
|
+
req.query["limit"],
|
|
103
|
+
DEFAULT_LIMIT,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const page: Array<UserProjectMembership> = rows.slice(
|
|
107
|
+
skip,
|
|
108
|
+
skip + limit,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
return Response.sendJsonArrayResponse(
|
|
112
|
+
req,
|
|
113
|
+
res,
|
|
114
|
+
page.map((row: UserProjectMembership) => {
|
|
115
|
+
return UserAPI.serializeUserProjectMembership(userId, row);
|
|
116
|
+
}),
|
|
117
|
+
new PositiveNumber(rows.length),
|
|
118
|
+
);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
return next(err);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
/*
|
|
126
|
+
* Removes one user from one project - every team they belong to in it - in
|
|
127
|
+
* a single call.
|
|
128
|
+
*
|
|
129
|
+
* A row on the User > Projects page is a project, so "remove" there means
|
|
130
|
+
* "remove from the project". Doing that as N separate DELETEs from the
|
|
131
|
+
* browser is not equivalent: TeamMemberService.onBeforeDelete refuses to
|
|
132
|
+
* remove the last accepted member of a team that shouldHaveAtLeastOneMember
|
|
133
|
+
* (the Owners team), and it refuses per request - so a client-side loop
|
|
134
|
+
* deletes every other membership first and only then reports the failure,
|
|
135
|
+
* leaving the user stripped of the teams the admin was just told they had
|
|
136
|
+
* not lost. One deleteBy over the whole set runs that guard against all of
|
|
137
|
+
* the user's memberships in the project before anything is deleted.
|
|
138
|
+
*
|
|
139
|
+
* This is the master-admin twin of
|
|
140
|
+
* POST /team-member/remove-user-from-project, which takes its project from
|
|
141
|
+
* the request's tenant. A master admin is not a member of the project and
|
|
142
|
+
* sends no tenant, so the project is named in the body here - the
|
|
143
|
+
* master-admin middleware, not a tenant, is what authorizes the call.
|
|
144
|
+
*
|
|
145
|
+
* The delete runs with the CALLER'S props rather than as root, so the
|
|
146
|
+
* Owners-team and SCIM Push Groups guards still apply: a master admin can
|
|
147
|
+
* remove people, but not leave a project ownerless or fight the customer's
|
|
148
|
+
* identity provider behind its back.
|
|
149
|
+
*/
|
|
150
|
+
this.router.post(
|
|
151
|
+
`${new this.entityType().getCrudApiPath()?.toString()}/:userId/remove-from-project`,
|
|
152
|
+
MasterAdminAuthorization.isAuthorizedMasterAdminMiddleware,
|
|
153
|
+
async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
|
|
154
|
+
try {
|
|
155
|
+
const userId: ObjectID = UserAPI.getUserIdFromParams(req);
|
|
156
|
+
|
|
157
|
+
const projectIdParam: string = (
|
|
158
|
+
(req.body?.["projectId"] as string) || ""
|
|
159
|
+
).trim();
|
|
160
|
+
|
|
161
|
+
if (!projectIdParam) {
|
|
162
|
+
return Response.sendErrorResponse(
|
|
163
|
+
req,
|
|
164
|
+
res,
|
|
165
|
+
new BadDataException("Project ID is required"),
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
ObjectID.validateUUID(projectIdParam);
|
|
170
|
+
|
|
171
|
+
const props: DatabaseCommonInteractionProps =
|
|
172
|
+
await CommonAPI.getDatabaseCommonInteractionProps(req);
|
|
173
|
+
|
|
174
|
+
const numberOfMembershipsDeleted: number =
|
|
175
|
+
await TeamMemberService.deleteBy({
|
|
176
|
+
query: {
|
|
177
|
+
userId: userId,
|
|
178
|
+
projectId: new ObjectID(projectIdParam),
|
|
179
|
+
} as Query<TeamMember>,
|
|
180
|
+
limit: LIMIT_MAX,
|
|
181
|
+
skip: 0,
|
|
182
|
+
props: props,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return Response.sendJsonObjectResponse(req, res, {
|
|
186
|
+
numberOfMembershipsDeleted: numberOfMembershipsDeleted,
|
|
187
|
+
});
|
|
188
|
+
} catch (err) {
|
|
189
|
+
return next(err);
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
|
|
19
194
|
this.router.get(
|
|
20
195
|
`${new this.entityType().getCrudApiPath()?.toString()}/profile-picture/:userId`,
|
|
21
196
|
async (req: ExpressRequest, res: ExpressResponse) => {
|
|
@@ -78,6 +253,93 @@ export default class UserAPI extends BaseAPI<User, UserServiceType> {
|
|
|
78
253
|
);
|
|
79
254
|
}
|
|
80
255
|
|
|
256
|
+
/**
|
|
257
|
+
* The `:userId` in the path, rejected loudly if it is not a uuid.
|
|
258
|
+
*
|
|
259
|
+
* Validating rather than trusting matters even behind the master-admin gate:
|
|
260
|
+
* the value flows into a query, and a malformed id should fail as bad input
|
|
261
|
+
* rather than reach the database layer.
|
|
262
|
+
*/
|
|
263
|
+
private static getUserIdFromParams(req: ExpressRequest): ObjectID {
|
|
264
|
+
const userIdParam: string = ((req.params["userId"] as string) || "").trim();
|
|
265
|
+
|
|
266
|
+
if (!userIdParam) {
|
|
267
|
+
throw new BadDataException("User ID is required");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
ObjectID.validateUUID(userIdParam);
|
|
271
|
+
|
|
272
|
+
return new ObjectID(userIdParam);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* A non-negative integer from a query string, or the fallback.
|
|
277
|
+
*
|
|
278
|
+
* Anything unparseable (missing, "abc", "-5", "1e9999") falls back rather
|
|
279
|
+
* than becoming NaN - a NaN skip/limit turns Array.slice into "return
|
|
280
|
+
* everything from 0", which would silently ignore paging instead of failing.
|
|
281
|
+
*/
|
|
282
|
+
private static getPositiveIntegerParam(
|
|
283
|
+
value: unknown,
|
|
284
|
+
fallback: number,
|
|
285
|
+
): number {
|
|
286
|
+
if (value === undefined || value === null || value === "") {
|
|
287
|
+
return fallback;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const parsed: number = Number(value.toString());
|
|
291
|
+
|
|
292
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < 0) {
|
|
293
|
+
return fallback;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return parsed;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* One grouped row as JSON.
|
|
301
|
+
*
|
|
302
|
+
* The row is sent as a TeamMember - the model the row is built from, and the
|
|
303
|
+
* one the Admin Dashboard's table is typed against - carrying the project it
|
|
304
|
+
* stands for. The aggregate fields (`teams`, the counts) are not columns of
|
|
305
|
+
* TeamMember, so they are attached after serialization; the client reads them
|
|
306
|
+
* off the raw JSON before hydrating the model.
|
|
307
|
+
*/
|
|
308
|
+
private static serializeUserProjectMembership(
|
|
309
|
+
userId: ObjectID,
|
|
310
|
+
row: UserProjectMembership,
|
|
311
|
+
): JSONObject {
|
|
312
|
+
const teamMember: TeamMember = new TeamMember();
|
|
313
|
+
|
|
314
|
+
if (row.id) {
|
|
315
|
+
teamMember._id = row.id;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
teamMember.userId = userId;
|
|
319
|
+
teamMember.hasAcceptedInvitation = row.hasAcceptedInvitation;
|
|
320
|
+
|
|
321
|
+
if (row.projectId) {
|
|
322
|
+
teamMember.projectId = row.projectId;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (row.project) {
|
|
326
|
+
teamMember.project = row.project;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (row.joinedAt) {
|
|
330
|
+
teamMember.createdAt = row.joinedAt;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const json: JSONObject = BaseModel.toJSON(teamMember, TeamMember);
|
|
334
|
+
|
|
335
|
+
json["teams"] = BaseModel.toJSONArray(row.teams, Team) as JSONArray;
|
|
336
|
+
json["teamCount"] = row.teams.length;
|
|
337
|
+
json["pendingTeamCount"] = row.pendingTeamCount;
|
|
338
|
+
json["teamMemberIds"] = [...row.teamMemberIds];
|
|
339
|
+
|
|
340
|
+
return json;
|
|
341
|
+
}
|
|
342
|
+
|
|
81
343
|
private sendBlankProfile(req: ExpressRequest, res: ExpressResponse): void {
|
|
82
344
|
Response.setNoCacheHeaders(res);
|
|
83
345
|
|
|
@@ -167,13 +167,43 @@ export const PostgresStatementTimeoutMs: number = parseInt(
|
|
|
167
167
|
10,
|
|
168
168
|
);
|
|
169
169
|
|
|
170
|
+
/*
|
|
171
|
+
* Postgres-side lock timeout (ms). Caps how long a statement will WAIT for a
|
|
172
|
+
* row/table lock before giving up — distinct from statement_timeout, which
|
|
173
|
+
* caps total execution.
|
|
174
|
+
*
|
|
175
|
+
* Without it, contention on a hot row degrades into a strictly-ordered queue:
|
|
176
|
+
* every waiter pins a backend for the sum of everyone ahead of it. That is the
|
|
177
|
+
* row-lock convoy that took production down — 892 connections parked on locks,
|
|
178
|
+
* the tail waiting 3.7 hours — and no amount of database capacity changes it,
|
|
179
|
+
* because the queue itself is the failure. A short lock_timeout converts an
|
|
180
|
+
* unbounded wait into a fast, retryable error.
|
|
181
|
+
*
|
|
182
|
+
* Must stay well below statement_timeout so a lock wait surfaces as
|
|
183
|
+
* `lock_not_available` (55P03) rather than a generic statement timeout — the
|
|
184
|
+
* two want very different handling.
|
|
185
|
+
*/
|
|
186
|
+
export const PostgresLockTimeoutMs: number = parseInt(
|
|
187
|
+
process.env["DATABASE_LOCK_TIMEOUT_MS"] || "3000",
|
|
188
|
+
10,
|
|
189
|
+
);
|
|
190
|
+
|
|
170
191
|
/*
|
|
171
192
|
* Node-postgres client-side query timeout (ms). Belt-and-braces for the
|
|
172
193
|
* server-side statement_timeout — fires even if the connection has gone
|
|
173
194
|
* silent or the server-side timeout doesn't kick in.
|
|
195
|
+
*
|
|
196
|
+
* Deliberately LONGER than statement_timeout. These two used to be equal, and
|
|
197
|
+
* because the client timer starts before the packet even reaches the backend,
|
|
198
|
+
* the client always won by a round trip — so the app never observed Postgres's
|
|
199
|
+
* real SQLSTATE and, worse, the client-side timeout only ABANDONS the query:
|
|
200
|
+
* the backend keeps running and keeps its place in the lock queue. Letting the
|
|
201
|
+
* server win means contention is cancelled server-side instead of accumulating
|
|
202
|
+
* invisibly behind a pooler.
|
|
174
203
|
*/
|
|
175
204
|
export const PostgresQueryTimeoutMs: number = parseInt(
|
|
176
|
-
process.env["DATABASE_QUERY_TIMEOUT_MS"] ||
|
|
205
|
+
process.env["DATABASE_QUERY_TIMEOUT_MS"] ||
|
|
206
|
+
String(PostgresStatementTimeoutMs + 5000),
|
|
177
207
|
10,
|
|
178
208
|
);
|
|
179
209
|
|
|
@@ -447,10 +477,14 @@ export const DisableQueueWorkers: boolean =
|
|
|
447
477
|
* When "false", this process does NOT run schema or data migrations on boot.
|
|
448
478
|
* Set on runtime pods (app/worker/nginx) when a dedicated one-shot migrate Job
|
|
449
479
|
* (App/Migrate.ts) owns migrations instead, so the fleet's many replicas never
|
|
450
|
-
* run them — which
|
|
451
|
-
*
|
|
480
|
+
* run them — which keeps boot DDL off pooled connections and, since the data
|
|
481
|
+
* migration runner no longer takes an advisory lock, is also what keeps two
|
|
482
|
+
* replicas from running the same migration concurrently.
|
|
483
|
+
*
|
|
452
484
|
* Default true preserves the original self-migrating-on-boot behavior used by
|
|
453
|
-
* docker-compose and any deploy that does not run the migrate Job.
|
|
485
|
+
* docker-compose and any deploy that does not run the migrate Job. Those
|
|
486
|
+
* deployments DO run several unserialized runners, so data migrations must be
|
|
487
|
+
* written to tolerate it (see Workers/Utils/DataMigration.ts).
|
|
454
488
|
*/
|
|
455
489
|
export const RunDatabaseMigrationsOnBoot: boolean =
|
|
456
490
|
process.env["RUN_DATABASE_MIGRATIONS_ON_BOOT"] !== "false";
|
|
@@ -176,6 +176,158 @@ export default abstract class GlobalCache {
|
|
|
176
176
|
await client.set(`${namespace}-${key}`, value, "EX", expiresInSeconds);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
/*
|
|
180
|
+
* Atomic acquire-once fence: SET ... EX ... NX. Returns true ONLY for the
|
|
181
|
+
* caller that created the key; every concurrent caller gets false until it
|
|
182
|
+
* expires.
|
|
183
|
+
*
|
|
184
|
+
* This exists because `getString()` followed by `setString()` is a
|
|
185
|
+
* check-then-act race, and at ingest concurrency that race is not
|
|
186
|
+
* theoretical — it is the whole problem. When N workers resolve the same
|
|
187
|
+
* row in the same instant they ALL read a miss and they ALL proceed, so a
|
|
188
|
+
* fence meant to admit one writer per window admits N. With 100 worker pods
|
|
189
|
+
* that turned a once-a-minute heartbeat into thousands of simultaneous
|
|
190
|
+
* UPDATEs against the same handful of rows, and the resulting row-lock
|
|
191
|
+
* convoy starved the Postgres connection pool (some statements queued for
|
|
192
|
+
* hours). Redis evaluates SET NX atomically, so exactly one caller wins no
|
|
193
|
+
* matter how many arrive together.
|
|
194
|
+
*
|
|
195
|
+
* Fence keys should carry the TTL jitter from `withJitter()` — see there for
|
|
196
|
+
* why synchronized expiry re-creates the herd this is meant to prevent.
|
|
197
|
+
*/
|
|
198
|
+
@CaptureSpan()
|
|
199
|
+
public static async setStringIfNotExists(
|
|
200
|
+
namespace: string,
|
|
201
|
+
key: string,
|
|
202
|
+
value: string,
|
|
203
|
+
options?: CacheSetOptions,
|
|
204
|
+
): Promise<boolean> {
|
|
205
|
+
const client: ClientType | null = Redis.getClient();
|
|
206
|
+
|
|
207
|
+
if (!client || !Redis.isConnected()) {
|
|
208
|
+
throw new DatabaseNotConnectedException("Cache is not connected");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const expiresInSeconds: number =
|
|
212
|
+
options?.expiresInSeconds ?? OneUptimeDate.getSecondsInDays(30);
|
|
213
|
+
|
|
214
|
+
const result: string | null = await client.set(
|
|
215
|
+
`${namespace}-${key}`,
|
|
216
|
+
value,
|
|
217
|
+
"EX",
|
|
218
|
+
expiresInSeconds,
|
|
219
|
+
"NX",
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
/*
|
|
223
|
+
* ioredis resolves to "OK" when the key was created and to null when it
|
|
224
|
+
* already existed. Anything else (a driver/protocol change) is treated as
|
|
225
|
+
* "did not acquire" — losing the fence is safe, winning it wrongly is not.
|
|
226
|
+
*/
|
|
227
|
+
return result === "OK";
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/*
|
|
231
|
+
* Atomic compare-and-claim: claim the window unless the key ALREADY holds
|
|
232
|
+
* `value`. Returns true only for the caller that claimed it.
|
|
233
|
+
*
|
|
234
|
+
* `setStringIfNotExists` is the right primitive for a presence fence and the
|
|
235
|
+
* wrong one for a fingerprint throttle. Plain NX fails whenever the key
|
|
236
|
+
* exists — including when it holds a STALE fingerprint — so a genuinely
|
|
237
|
+
* changed payload (a new service.version after a deploy, a changed host IP)
|
|
238
|
+
* would be suppressed for the whole window and nobody would persist it. This
|
|
239
|
+
* keeps the bust-on-change behaviour that callers depend on while collapsing
|
|
240
|
+
* the GET-then-SET race into one atomic evaluation.
|
|
241
|
+
*
|
|
242
|
+
* The key is passed as KEYS[1] rather than inlined into the script body so
|
|
243
|
+
* the script stays correct on Redis Cluster, which routes by declared keys.
|
|
244
|
+
*/
|
|
245
|
+
@CaptureSpan()
|
|
246
|
+
public static async setStringIfChanged(
|
|
247
|
+
namespace: string,
|
|
248
|
+
key: string,
|
|
249
|
+
value: string,
|
|
250
|
+
options?: CacheSetOptions,
|
|
251
|
+
): Promise<boolean> {
|
|
252
|
+
const client: ClientType | null = Redis.getClient();
|
|
253
|
+
|
|
254
|
+
if (!client || !Redis.isConnected()) {
|
|
255
|
+
throw new DatabaseNotConnectedException("Cache is not connected");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const expiresInSeconds: number =
|
|
259
|
+
options?.expiresInSeconds ?? OneUptimeDate.getSecondsInDays(30);
|
|
260
|
+
|
|
261
|
+
const result: unknown = await client.eval(
|
|
262
|
+
"if redis.call('GET', KEYS[1]) == ARGV[1] then return 0 " +
|
|
263
|
+
"else redis.call('SET', KEYS[1], ARGV[1], 'EX', ARGV[2]) return 1 end",
|
|
264
|
+
1,
|
|
265
|
+
`${namespace}-${key}`,
|
|
266
|
+
value,
|
|
267
|
+
String(expiresInSeconds),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
return result === 1;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/*
|
|
274
|
+
* Spread a fence TTL over [ttl, ttl + 25%].
|
|
275
|
+
*
|
|
276
|
+
* A fixed TTL makes every fence for a fleet of rows expire in lockstep once
|
|
277
|
+
* their writes have been aligned by a common event — a deploy, a worker
|
|
278
|
+
* scale-up, a Redis restart. The window then reopens for thousands of rows
|
|
279
|
+
* in the same second and the herd re-forms on a one-minute period. Jitter
|
|
280
|
+
* breaks that alignment permanently: the fences drift apart after the first
|
|
281
|
+
* window and stay apart.
|
|
282
|
+
*
|
|
283
|
+
* The upper bound stays well inside the 15-minute disconnection sweep, so a
|
|
284
|
+
* jittered heartbeat can never make a live resource look disconnected.
|
|
285
|
+
*/
|
|
286
|
+
public static withJitter(expiresInSeconds: number): number {
|
|
287
|
+
if (expiresInSeconds <= 0) {
|
|
288
|
+
return expiresInSeconds;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return Math.ceil(expiresInSeconds * (1 + Math.random() * 0.25));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/*
|
|
295
|
+
* Atomic compare-and-delete: drop the key only if it still holds `value`.
|
|
296
|
+
* Returns true only when this caller's value was the one removed.
|
|
297
|
+
*
|
|
298
|
+
* This is the release half of a lease taken with `setStringIfNotExists`, and
|
|
299
|
+
* the comparison is what makes the release safe. A plain `deleteKey` is a
|
|
300
|
+
* check-then-act race in disguise: if the holder overruns its TTL the key
|
|
301
|
+
* expires, a second worker legitimately acquires the lease, and the first
|
|
302
|
+
* worker's release then deletes the SECOND worker's lease — handing the same
|
|
303
|
+
* lease to a third. Comparing the holder token collapses that into one
|
|
304
|
+
* atomic evaluation, so a late release is a no-op instead of a double-grant.
|
|
305
|
+
*
|
|
306
|
+
* The key is passed as KEYS[1] rather than inlined into the script body so
|
|
307
|
+
* the script stays correct on Redis Cluster, which routes by declared keys.
|
|
308
|
+
*/
|
|
309
|
+
@CaptureSpan()
|
|
310
|
+
public static async deleteKeyIfValue(
|
|
311
|
+
namespace: string,
|
|
312
|
+
key: string,
|
|
313
|
+
value: string,
|
|
314
|
+
): Promise<boolean> {
|
|
315
|
+
const client: ClientType | null = Redis.getClient();
|
|
316
|
+
|
|
317
|
+
if (!client || !Redis.isConnected()) {
|
|
318
|
+
throw new DatabaseNotConnectedException("Cache is not connected");
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const result: unknown = await client.eval(
|
|
322
|
+
"if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end",
|
|
323
|
+
1,
|
|
324
|
+
`${namespace}-${key}`,
|
|
325
|
+
value,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
return result === 1;
|
|
329
|
+
}
|
|
330
|
+
|
|
179
331
|
@CaptureSpan()
|
|
180
332
|
public static async deleteKey(namespace: string, key: string): Promise<void> {
|
|
181
333
|
const client: ClientType | null = Redis.getClient();
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
DatabaseUsername,
|
|
11
11
|
MaxPostgresConnections,
|
|
12
12
|
PostgresConnectionAcquireTimeoutMs,
|
|
13
|
+
PostgresLockTimeoutMs,
|
|
13
14
|
PostgresIdleInTransactionTimeoutMs,
|
|
14
15
|
PostgresIdleSessionTimeoutMs,
|
|
15
16
|
PostgresIdleTimeoutMs,
|
|
@@ -61,6 +62,21 @@ const dataSourceOptions: DataSourceOptions = {
|
|
|
61
62
|
statement_timeout: PostgresStatementTimeoutMs,
|
|
62
63
|
query_timeout: PostgresQueryTimeoutMs,
|
|
63
64
|
idle_in_transaction_session_timeout: PostgresIdleInTransactionTimeoutMs,
|
|
65
|
+
/*
|
|
66
|
+
* Bound how long a statement WAITS for a lock, so contention on a hot row
|
|
67
|
+
* fails fast instead of forming a queue (see PostgresLockTimeoutMs).
|
|
68
|
+
*
|
|
69
|
+
* Excluded on the migration path, and that exclusion is load-bearing:
|
|
70
|
+
* App/Migrate.ts loads these same options and connects DIRECTLY to the
|
|
71
|
+
* backend (bypassing any pooler), where startup parameters really do take
|
|
72
|
+
* effect. A 3s lock_timeout there would abort ACCESS EXCLUSIVE DDL on any
|
|
73
|
+
* table with live traffic — only the two migrations that set their own
|
|
74
|
+
* `SET LOCAL lock_timeout` expect to fail that way; the rest must be free
|
|
75
|
+
* to wait.
|
|
76
|
+
*/
|
|
77
|
+
...(PostgresLockTimeoutMs > 0 && !RunDatabaseMigrationsOnBoot
|
|
78
|
+
? { lock_timeout: PostgresLockTimeoutMs }
|
|
79
|
+
: {}),
|
|
64
80
|
/*
|
|
65
81
|
* Detect dead TCP peers (ungraceful client exit / network partition) so
|
|
66
82
|
* orphaned server-side connections get torn down instead of lingering
|
package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class AddStatusPageMonitorRule1786005052769
|
|
4
|
+
implements MigrationInterface
|
|
5
|
+
{
|
|
6
|
+
public name = "AddStatusPageMonitorRule1786005052769";
|
|
7
|
+
|
|
8
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
9
|
+
await queryRunner.query(
|
|
10
|
+
`CREATE TABLE "StatusPageMonitorRule" ("_id" uuid NOT NULL DEFAULT uuid_generate_v4(), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "deletedAt" TIMESTAMP WITH TIME ZONE, "version" integer NOT NULL, "projectId" uuid NOT NULL, "statusPageId" uuid NOT NULL, "name" character varying(100) NOT NULL, "description" character varying(500), "isEnabled" boolean NOT NULL DEFAULT true, "monitorNamePattern" character varying(500), "monitorDescriptionPattern" character varying(500), "statusPageGroupId" uuid, "showCurrentStatus" boolean NOT NULL DEFAULT true, "showUptimePercent" boolean NOT NULL DEFAULT true, "uptimePercentPrecision" character varying, "showStatusHistoryChart" boolean NOT NULL DEFAULT true, "createdByUserId" uuid, "deletedByUserId" uuid, CONSTRAINT "PK_f8d44792805d19b9a80921b6aa6" PRIMARY KEY ("_id"))`,
|
|
11
|
+
);
|
|
12
|
+
await queryRunner.query(
|
|
13
|
+
`CREATE INDEX "IDX_1dfd95ad32f7b687ef4d7ba591" ON "StatusPageMonitorRule" ("projectId") `,
|
|
14
|
+
);
|
|
15
|
+
await queryRunner.query(
|
|
16
|
+
`CREATE INDEX "IDX_473317deaa55a8305a047e4098" ON "StatusPageMonitorRule" ("statusPageId") `,
|
|
17
|
+
);
|
|
18
|
+
await queryRunner.query(
|
|
19
|
+
`CREATE INDEX "IDX_61196848685b7e7f5a6a54278b" ON "StatusPageMonitorRule" ("name") `,
|
|
20
|
+
);
|
|
21
|
+
await queryRunner.query(
|
|
22
|
+
`CREATE INDEX "IDX_71d1869039530178fd5f7e6faa" ON "StatusPageMonitorRule" ("isEnabled") `,
|
|
23
|
+
);
|
|
24
|
+
await queryRunner.query(
|
|
25
|
+
`CREATE INDEX "IDX_3e6d0bc4d444371aaa13a1c14c" ON "StatusPageMonitorRule" ("statusPageGroupId") `,
|
|
26
|
+
);
|
|
27
|
+
await queryRunner.query(
|
|
28
|
+
`CREATE TABLE "StatusPageMonitorRuleMonitorLabel" ("statusPageMonitorRuleId" uuid NOT NULL, "labelId" uuid NOT NULL, CONSTRAINT "PK_59234d33b435d8e771cd3728ea4" PRIMARY KEY ("statusPageMonitorRuleId", "labelId"))`,
|
|
29
|
+
);
|
|
30
|
+
await queryRunner.query(
|
|
31
|
+
`CREATE INDEX "IDX_0eb2b2a3601ea9813b8e162bd3" ON "StatusPageMonitorRuleMonitorLabel" ("statusPageMonitorRuleId") `,
|
|
32
|
+
);
|
|
33
|
+
await queryRunner.query(
|
|
34
|
+
`CREATE INDEX "IDX_bc08b888a870ecc9167516230a" ON "StatusPageMonitorRuleMonitorLabel" ("labelId") `,
|
|
35
|
+
);
|
|
36
|
+
await queryRunner.query(
|
|
37
|
+
`ALTER TABLE "StatusPageResource" ADD "statusPageMonitorRuleId" uuid`,
|
|
38
|
+
);
|
|
39
|
+
await queryRunner.query(
|
|
40
|
+
`CREATE INDEX "IDX_4e1ed45d9506da817dc7811601" ON "StatusPageResource" ("statusPageMonitorRuleId") `,
|
|
41
|
+
);
|
|
42
|
+
await queryRunner.query(
|
|
43
|
+
`ALTER TABLE "StatusPageMonitorRule" ADD CONSTRAINT "FK_1dfd95ad32f7b687ef4d7ba5910" FOREIGN KEY ("projectId") REFERENCES "Project"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
44
|
+
);
|
|
45
|
+
await queryRunner.query(
|
|
46
|
+
`ALTER TABLE "StatusPageMonitorRule" ADD CONSTRAINT "FK_473317deaa55a8305a047e4098b" FOREIGN KEY ("statusPageId") REFERENCES "StatusPage"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
47
|
+
);
|
|
48
|
+
await queryRunner.query(
|
|
49
|
+
`ALTER TABLE "StatusPageMonitorRule" ADD CONSTRAINT "FK_3e6d0bc4d444371aaa13a1c14cc" FOREIGN KEY ("statusPageGroupId") REFERENCES "StatusPageGroup"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
50
|
+
);
|
|
51
|
+
await queryRunner.query(
|
|
52
|
+
`ALTER TABLE "StatusPageMonitorRule" ADD CONSTRAINT "FK_60d22031be1695cbd1405376cbf" FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
53
|
+
);
|
|
54
|
+
await queryRunner.query(
|
|
55
|
+
`ALTER TABLE "StatusPageMonitorRule" ADD CONSTRAINT "FK_3416ec12899c9dde670d8dea290" FOREIGN KEY ("deletedByUserId") REFERENCES "User"("_id") ON DELETE SET NULL ON UPDATE NO ACTION`,
|
|
56
|
+
);
|
|
57
|
+
await queryRunner.query(
|
|
58
|
+
`ALTER TABLE "StatusPageResource" ADD CONSTRAINT "FK_4e1ed45d9506da817dc78116010" FOREIGN KEY ("statusPageMonitorRuleId") REFERENCES "StatusPageMonitorRule"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
|
|
59
|
+
);
|
|
60
|
+
await queryRunner.query(
|
|
61
|
+
`ALTER TABLE "StatusPageMonitorRuleMonitorLabel" ADD CONSTRAINT "FK_0eb2b2a3601ea9813b8e162bd3b" FOREIGN KEY ("statusPageMonitorRuleId") REFERENCES "StatusPageMonitorRule"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
|
|
62
|
+
);
|
|
63
|
+
await queryRunner.query(
|
|
64
|
+
`ALTER TABLE "StatusPageMonitorRuleMonitorLabel" ADD CONSTRAINT "FK_bc08b888a870ecc9167516230ad" FOREIGN KEY ("labelId") REFERENCES "Label"("_id") ON DELETE CASCADE ON UPDATE CASCADE`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
69
|
+
await queryRunner.query(
|
|
70
|
+
`ALTER TABLE "StatusPageMonitorRuleMonitorLabel" DROP CONSTRAINT "FK_bc08b888a870ecc9167516230ad"`,
|
|
71
|
+
);
|
|
72
|
+
await queryRunner.query(
|
|
73
|
+
`ALTER TABLE "StatusPageMonitorRuleMonitorLabel" DROP CONSTRAINT "FK_0eb2b2a3601ea9813b8e162bd3b"`,
|
|
74
|
+
);
|
|
75
|
+
await queryRunner.query(
|
|
76
|
+
`ALTER TABLE "StatusPageResource" DROP CONSTRAINT "FK_4e1ed45d9506da817dc78116010"`,
|
|
77
|
+
);
|
|
78
|
+
await queryRunner.query(
|
|
79
|
+
`ALTER TABLE "StatusPageMonitorRule" DROP CONSTRAINT "FK_3416ec12899c9dde670d8dea290"`,
|
|
80
|
+
);
|
|
81
|
+
await queryRunner.query(
|
|
82
|
+
`ALTER TABLE "StatusPageMonitorRule" DROP CONSTRAINT "FK_60d22031be1695cbd1405376cbf"`,
|
|
83
|
+
);
|
|
84
|
+
await queryRunner.query(
|
|
85
|
+
`ALTER TABLE "StatusPageMonitorRule" DROP CONSTRAINT "FK_3e6d0bc4d444371aaa13a1c14cc"`,
|
|
86
|
+
);
|
|
87
|
+
await queryRunner.query(
|
|
88
|
+
`ALTER TABLE "StatusPageMonitorRule" DROP CONSTRAINT "FK_473317deaa55a8305a047e4098b"`,
|
|
89
|
+
);
|
|
90
|
+
await queryRunner.query(
|
|
91
|
+
`ALTER TABLE "StatusPageMonitorRule" DROP CONSTRAINT "FK_1dfd95ad32f7b687ef4d7ba5910"`,
|
|
92
|
+
);
|
|
93
|
+
await queryRunner.query(
|
|
94
|
+
`DROP INDEX "public"."IDX_4e1ed45d9506da817dc7811601"`,
|
|
95
|
+
);
|
|
96
|
+
await queryRunner.query(
|
|
97
|
+
`ALTER TABLE "StatusPageResource" DROP COLUMN "statusPageMonitorRuleId"`,
|
|
98
|
+
);
|
|
99
|
+
await queryRunner.query(
|
|
100
|
+
`DROP INDEX "public"."IDX_bc08b888a870ecc9167516230a"`,
|
|
101
|
+
);
|
|
102
|
+
await queryRunner.query(
|
|
103
|
+
`DROP INDEX "public"."IDX_0eb2b2a3601ea9813b8e162bd3"`,
|
|
104
|
+
);
|
|
105
|
+
await queryRunner.query(`DROP TABLE "StatusPageMonitorRuleMonitorLabel"`);
|
|
106
|
+
await queryRunner.query(
|
|
107
|
+
`DROP INDEX "public"."IDX_3e6d0bc4d444371aaa13a1c14c"`,
|
|
108
|
+
);
|
|
109
|
+
await queryRunner.query(
|
|
110
|
+
`DROP INDEX "public"."IDX_71d1869039530178fd5f7e6faa"`,
|
|
111
|
+
);
|
|
112
|
+
await queryRunner.query(
|
|
113
|
+
`DROP INDEX "public"."IDX_61196848685b7e7f5a6a54278b"`,
|
|
114
|
+
);
|
|
115
|
+
await queryRunner.query(
|
|
116
|
+
`DROP INDEX "public"."IDX_473317deaa55a8305a047e4098"`,
|
|
117
|
+
);
|
|
118
|
+
await queryRunner.query(
|
|
119
|
+
`DROP INDEX "public"."IDX_1dfd95ad32f7b687ef4d7ba591"`,
|
|
120
|
+
);
|
|
121
|
+
await queryRunner.query(`DROP TABLE "StatusPageMonitorRule"`);
|
|
122
|
+
}
|
|
123
|
+
}
|
package/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
2
|
+
|
|
3
|
+
export class AddPerUserPasswordSalt1786018109307 implements MigrationInterface {
|
|
4
|
+
public name = "AddPerUserPasswordSalt1786018109307";
|
|
5
|
+
|
|
6
|
+
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
7
|
+
await queryRunner.query(
|
|
8
|
+
`ALTER TABLE "User" ADD "passwordSalt" character varying(100)`,
|
|
9
|
+
);
|
|
10
|
+
await queryRunner.query(
|
|
11
|
+
`ALTER TABLE "StatusPagePrivateUser" ADD "passwordSalt" character varying(100)`,
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
16
|
+
await queryRunner.query(
|
|
17
|
+
`ALTER TABLE "StatusPagePrivateUser" DROP COLUMN "passwordSalt"`,
|
|
18
|
+
);
|
|
19
|
+
await queryRunner.query(`ALTER TABLE "User" DROP COLUMN "passwordSalt"`);
|
|
20
|
+
}
|
|
21
|
+
}
|